aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COFF/Chunks.cpp327
-rw-r--r--COFF/Chunks.h121
-rw-r--r--COFF/Config.h5
-rw-r--r--COFF/DLL.cpp102
-rw-r--r--COFF/DLL.h9
-rw-r--r--COFF/Driver.cpp553
-rw-r--r--COFF/Driver.h4
-rw-r--r--COFF/DriverUtils.cpp24
-rw-r--r--COFF/ICF.cpp27
-rw-r--r--COFF/InputFiles.cpp95
-rw-r--r--COFF/InputFiles.h30
-rw-r--r--COFF/LTO.cpp3
-rw-r--r--COFF/MapFile.cpp2
-rw-r--r--COFF/MarkLive.cpp8
-rw-r--r--COFF/MinGW.cpp42
-rw-r--r--COFF/MinGW.h6
-rw-r--r--COFF/Options.td37
-rw-r--r--COFF/PDB.cpp997
-rw-r--r--COFF/PDB.h2
-rw-r--r--COFF/SymbolTable.cpp185
-rw-r--r--COFF/SymbolTable.h8
-rw-r--r--COFF/Symbols.cpp9
-rw-r--r--COFF/Symbols.h14
-rw-r--r--COFF/Writer.cpp723
-rw-r--r--COFF/Writer.h6
-rw-r--r--Common/Args.cpp9
-rw-r--r--Common/ErrorHandler.cpp5
-rw-r--r--Common/Strings.cpp33
-rw-r--r--Common/TargetOptionsCommandFlags.cpp1
-rw-r--r--ELF/AArch64ErrataFix.cpp27
-rw-r--r--ELF/Arch/AArch64.cpp37
-rw-r--r--ELF/Arch/AMDGPU.cpp1
-rw-r--r--ELF/Arch/ARM.cpp124
-rw-r--r--ELF/Arch/AVR.cpp3
-rw-r--r--ELF/Arch/Hexagon.cpp195
-rw-r--r--ELF/Arch/MSP430.cpp94
-rw-r--r--ELF/Arch/Mips.cpp13
-rw-r--r--ELF/Arch/PPC.cpp5
-rw-r--r--ELF/Arch/PPC64.cpp473
-rw-r--r--ELF/Arch/RISCV.cpp279
-rw-r--r--ELF/Arch/SPARCV9.cpp1
-rw-r--r--ELF/Arch/X86.cpp25
-rw-r--r--ELF/Arch/X86_64.cpp50
-rw-r--r--ELF/CMakeLists.txt4
-rw-r--r--ELF/CallGraphSort.cpp51
-rw-r--r--ELF/Config.h11
-rw-r--r--ELF/DWARF.cpp (renamed from ELF/GdbIndex.cpp)40
-rw-r--r--ELF/DWARF.h (renamed from ELF/GdbIndex.h)69
-rw-r--r--ELF/Driver.cpp378
-rw-r--r--ELF/Driver.h3
-rw-r--r--ELF/DriverUtils.cpp5
-rw-r--r--ELF/EhFrame.cpp4
-rw-r--r--ELF/ICF.cpp32
-rw-r--r--ELF/InputFiles.cpp111
-rw-r--r--ELF/InputFiles.h12
-rw-r--r--ELF/InputSection.cpp459
-rw-r--r--ELF/InputSection.h38
-rw-r--r--ELF/LTO.cpp48
-rw-r--r--ELF/LTO.h2
-rw-r--r--ELF/LinkerScript.cpp55
-rw-r--r--ELF/LinkerScript.h12
-rw-r--r--ELF/MapFile.cpp11
-rw-r--r--ELF/MarkLive.cpp15
-rw-r--r--ELF/Options.td21
-rw-r--r--ELF/OutputSections.cpp28
-rw-r--r--ELF/OutputSections.h6
-rw-r--r--ELF/Relocations.cpp363
-rw-r--r--ELF/Relocations.h39
-rw-r--r--ELF/ScriptLexer.cpp9
-rw-r--r--ELF/ScriptLexer.h1
-rw-r--r--ELF/ScriptParser.cpp153
-rw-r--r--ELF/SymbolTable.cpp250
-rw-r--r--ELF/SymbolTable.h34
-rw-r--r--ELF/Symbols.cpp60
-rw-r--r--ELF/Symbols.h66
-rw-r--r--ELF/SyntheticSections.cpp506
-rw-r--r--ELF/SyntheticSections.h137
-rw-r--r--ELF/Target.cpp13
-rw-r--r--ELF/Target.h64
-rw-r--r--ELF/Thunks.cpp298
-rw-r--r--ELF/Writer.cpp697
-rw-r--r--LICENSE.TXT2
-rw-r--r--MinGW/Driver.cpp31
-rw-r--r--MinGW/Options.td3
-rw-r--r--docs/NewLLD.rst14
-rw-r--r--docs/README.txt5
-rw-r--r--docs/Readers.rst2
-rw-r--r--docs/ReleaseNotes.rst57
-rw-r--r--docs/WebAssembly.rst106
-rw-r--r--docs/conf.py4
-rw-r--r--docs/index.rst20
-rw-r--r--docs/ld.lld.155
-rw-r--r--docs/missingkeyfunction.rst84
-rw-r--r--docs/open_projects.rst2
-rw-r--r--docs/windows_support.rst4
-rw-r--r--include/lld/Common/Args.h3
-rw-r--r--include/lld/Common/ErrorHandler.h2
-rw-r--r--include/lld/Common/LLVM.h100
-rw-r--r--include/lld/Common/Strings.h3
-rw-r--r--include/lld/Common/TargetOptionsCommandFlags.h1
-rw-r--r--include/lld/Common/Threads.h2
-rw-r--r--include/lld/Core/TODO.txt14
-rw-r--r--lib/Driver/DarwinLdDriver.cpp11
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp1
-rw-r--r--lib/ReaderWriter/MachO/MachOLinkingContext.cpp1
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h9
-rw-r--r--test/CMakeLists.txt3
-rw-r--r--test/COFF/Inputs/associative-comdat-mingw-2.s34
-rw-r--r--test/COFF/Inputs/bad-block-size.pdb2
-rw-r--r--test/COFF/Inputs/comdat-jumptable2.s35
-rw-r--r--test/COFF/Inputs/common-replacement.s5
-rw-r--r--test/COFF/Inputs/crt-dyn-initializer-order_1.yaml15
-rw-r--r--test/COFF/Inputs/crt-dyn-initializer-order_2.yaml19
-rw-r--r--test/COFF/Inputs/empty.yaml67
-rw-r--r--test/COFF/Inputs/far-arm-thumb-abs.s2
-rw-r--r--test/COFF/Inputs/far-arm-thumb-abs20.s2
-rw-r--r--test/COFF/Inputs/gnu-implib-data.s23
-rw-r--r--test/COFF/Inputs/gnu-implib-func.s27
-rw-r--r--test/COFF/Inputs/gnu-implib-head.s13
-rw-r--r--test/COFF/Inputs/gnu-implib-tail.s11
-rw-r--r--test/COFF/Inputs/gnu-weak.obin0 -> 1468 bytes
-rw-r--r--test/COFF/Inputs/gnu-weak2.obin0 -> 874 bytes
-rw-r--r--test/COFF/Inputs/icf-safe.s9
-rw-r--r--test/COFF/Inputs/inline-weak.obin0 -> 1625 bytes
-rw-r--r--test/COFF/Inputs/inline-weak2.obin0 -> 1389 bytes
-rw-r--r--test/COFF/Inputs/pdb-file-statics-a.yaml6
-rw-r--r--test/COFF/Inputs/pdb-file-statics-b.yaml2
-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-missing-2.yaml32
-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-type-server-valid-signature.yaml121
-rw-r--r--test/COFF/Inputs/precomp-a.objbin0 -> 2598 bytes
-rw-r--r--test/COFF/Inputs/precomp-b.objbin0 -> 2257 bytes
-rw-r--r--test/COFF/Inputs/precomp-invalid.objbin0 -> 2257 bytes
-rw-r--r--test/COFF/Inputs/precomp.objbin0 -> 62392 bytes
-rw-r--r--test/COFF/arm-thumb-branch-error.s10
-rw-r--r--test/COFF/arm-thumb-branch20-error.s12
-rw-r--r--test/COFF/arm-thumb-thunks-multipass.s70
-rw-r--r--test/COFF/arm-thumb-thunks.s75
-rw-r--r--test/COFF/arm64-delayimport.yaml91
-rw-r--r--test/COFF/arm64-localimport-align.s24
-rw-r--r--test/COFF/arm64-relocs-imports.test18
-rw-r--r--test/COFF/associative-comdat-mingw.s74
-rw-r--r--test/COFF/autoimport-arm-code.s19
-rw-r--r--test/COFF/autoimport-arm-data.s42
-rw-r--r--test/COFF/autoimport-arm64-code.s18
-rw-r--r--test/COFF/autoimport-arm64-data.s42
-rw-r--r--test/COFF/autoimport-gnu-implib.s26
-rw-r--r--test/COFF/autoimport-list-ptrs.s20
-rw-r--r--test/COFF/autoimport-refptr.s65
-rw-r--r--test/COFF/autoimport-x86.s53
-rw-r--r--test/COFF/baserel.test6
-rw-r--r--test/COFF/broken-arm-reloc.yaml92
-rw-r--r--test/COFF/comdat-jumptable.s70
-rw-r--r--test/COFF/comdat-weak.test82
-rw-r--r--test/COFF/common-replacement.s35
-rw-r--r--test/COFF/could-not-open.test5
-rw-r--r--test/COFF/crt-dyn-initializer-order.test100
-rw-r--r--test/COFF/ctors_dtors_priority.s35
-rw-r--r--test/COFF/debug-fastlink.test12
-rw-r--r--test/COFF/debug-reloc.s18
-rw-r--r--test/COFF/directives.s46
-rw-r--r--test/COFF/duplicate-imp-func.s43
-rw-r--r--test/COFF/entry-inference-mingw.s44
-rw-r--r--test/COFF/entry-inference.test8
-rw-r--r--test/COFF/entry-inference3.test10
-rw-r--r--test/COFF/entry-inference332.test39
-rw-r--r--test/COFF/entry-inference4.test68
-rw-r--r--test/COFF/export-all.s27
-rw-r--r--test/COFF/export.test9
-rw-r--r--test/COFF/force-multiple.test45
-rw-r--r--test/COFF/gfids-export.s44
-rw-r--r--test/COFF/gfids-relocations32.s87
-rw-r--r--test/COFF/gfids-relocations64.s76
-rw-r--r--test/COFF/gnu-weak.test52
-rw-r--r--test/COFF/guardcf-align.s1
-rw-r--r--test/COFF/header-size.s12
-rw-r--r--test/COFF/icf-safe.s37
-rw-r--r--test/COFF/ignore-many.test16
-rw-r--r--test/COFF/imports-gnu-autoexport.s25
-rw-r--r--test/COFF/imports-gnu-only.s28
-rw-r--r--test/COFF/imports-gnu.test29
-rw-r--r--test/COFF/invalid-debug-type.test3
-rw-r--r--test/COFF/invalid-debug.test6
-rw-r--r--test/COFF/libname-mingw.test8
-rw-r--r--test/COFF/line-error.yaml160
-rw-r--r--test/COFF/lto-cache.ll2
-rw-r--r--test/COFF/lto-chkstk.ll1
-rw-r--r--test/COFF/lto-cpu-string.ll21
-rw-r--r--test/COFF/msvclto-archive.ll40
-rw-r--r--test/COFF/msvclto-order.ll25
-rw-r--r--test/COFF/msvclto.ll20
-rw-r--r--test/COFF/no-idata.s20
-rw-r--r--test/COFF/pdb-debug-f.s28
-rw-r--r--test/COFF/pdb-framedata.yaml462
-rw-r--r--test/COFF/pdb-global-hashes.test6
-rw-r--r--test/COFF/pdb-globals.test6
-rw-r--r--test/COFF/pdb-heapsite.yaml2
-rw-r--r--test/COFF/pdb-linker-module.test6
-rw-r--r--test/COFF/pdb-options.test5
-rw-r--r--test/COFF/pdb-procid-remapping.test2
-rw-r--r--test/COFF/pdb-relative-source-lines.test98
-rw-r--r--test/COFF/pdb-same-name.test4
-rw-r--r--test/COFF/pdb-symbol-types.yaml8
-rw-r--r--test/COFF/pdb-thunk.yaml12
-rw-r--r--test/COFF/pdb-type-server-invalid-signature.yaml140
-rw-r--r--test/COFF/pdb-type-server-missing.yaml21
-rw-r--r--test/COFF/pdb-type-server-native-errors.yaml130
-rw-r--r--test/COFF/pdb-type-server-simple.test12
-rw-r--r--test/COFF/pdb.test19
-rw-r--r--test/COFF/pdbaltpath.test39
-rw-r--r--test/COFF/precomp-link.test42
-rw-r--r--test/COFF/reloc-discarded.s1
-rw-r--r--test/COFF/rsds.test126
-rw-r--r--test/COFF/s_udt.s476
-rw-r--r--test/COFF/subsystem-inference-mingw.s17
-rw-r--r--test/COFF/subsystem-inference2.test54
-rw-r--r--test/COFF/subsystem-inference32.test74
-rw-r--r--test/COFF/thinlto-archives.ll12
-rw-r--r--test/COFF/undefined-symbol-cv.s10
-rw-r--r--test/COFF/undefined-symbol.s12
-rw-r--r--test/COFF/wholearchive.s1
-rw-r--r--test/ELF/Inputs/bad-reloc-target.test21
-rw-r--r--test/ELF/Inputs/copy-rel-tls.s12
-rw-r--r--test/ELF/Inputs/gdb-index-invalid-ranges.obj.s2
-rw-r--r--test/ELF/Inputs/gdb-index-multiple-cu-2.s45
-rw-r--r--test/ELF/Inputs/hexagon-shared.s3
-rw-r--r--test/ELF/Inputs/i386-linkonce.s11
-rw-r--r--test/ELF/Inputs/ppc64-bsymbolic-local-def.s14
-rw-r--r--test/ELF/Inputs/ppc64-no-split-stack.s8
-rw-r--r--test/ELF/Inputs/ppc64-tls-ie-le.s29
-rw-r--r--test/ELF/Inputs/ppc64le-quadword-ldst.obin0 -> 1032 bytes
-rw-r--r--test/ELF/Inputs/wrap-with-archive.s5
-rw-r--r--test/ELF/Inputs/x86-64-split-stack-extra.s10
-rw-r--r--test/ELF/aarch64-abs16.s20
-rw-r--r--test/ELF/aarch64-abs32.s20
-rw-r--r--test/ELF/aarch64-call26-thunk.s10
-rw-r--r--test/ELF/aarch64-combined-dynrel-ifunc.s51
-rw-r--r--test/ELF/aarch64-combined-dynrel.s41
-rw-r--r--test/ELF/aarch64-condb-reloc.s30
-rw-r--r--test/ELF/aarch64-copy.s32
-rw-r--r--test/ELF/aarch64-copy2.s2
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-abs-mapsyms.s22
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-cli.s2
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-large.s74
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-large2.s19
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-recognize.s490
-rw-r--r--test/ELF/aarch64-cortex-a53-843419-tlsrelax.s38
-rw-r--r--test/ELF/aarch64-data-relocs.s4
-rw-r--r--test/ELF/aarch64-gnu-ifunc-address.s40
-rw-r--r--test/ELF/aarch64-gnu-ifunc-plt.s80
-rw-r--r--test/ELF/aarch64-gnu-ifunc.s46
-rw-r--r--test/ELF/aarch64-gnu-ifunc2.s52
-rw-r--r--test/ELF/aarch64-gnu-ifunc3.s49
-rw-r--r--test/ELF/aarch64-jump26-thunk.s10
-rw-r--r--test/ELF/aarch64-lo12-alignment.s8
-rw-r--r--test/ELF/aarch64-prel16.s24
-rw-r--r--test/ELF/aarch64-prel32.s24
-rw-r--r--test/ELF/aarch64-relocs.s50
-rw-r--r--test/ELF/aarch64-thunk-pi.s4
-rw-r--r--test/ELF/aarch64-thunk-section-location.s8
-rw-r--r--test/ELF/aarch64-tls-gdie.s14
-rw-r--r--test/ELF/aarch64-tls-gdle.s12
-rw-r--r--test/ELF/aarch64-tls-ie.s22
-rw-r--r--test/ELF/aarch64-tls-iele.s10
-rw-r--r--test/ELF/aarch64-tls-le.s29
-rw-r--r--test/ELF/aarch64-tlsld-ldst.s52
-rw-r--r--test/ELF/aarch64-tstbr14-reloc.s26
-rw-r--r--test/ELF/aarch64-undefined-weak.s24
-rw-r--r--test/ELF/amdgpu-elf-flags-err.s4
-rw-r--r--test/ELF/amdgpu-elf-flags.s4
-rw-r--r--test/ELF/amdgpu-kernels.s2
-rw-r--r--test/ELF/archive-fetch.s15
-rw-r--r--test/ELF/arm-bl-v6-inrange.s47
-rw-r--r--test/ELF/arm-bl-v6.s33
-rw-r--r--test/ELF/arm-blx-v4t.s7
-rw-r--r--test/ELF/arm-branch-rangethunk.s6
-rw-r--r--test/ELF/arm-branch-undef-weak-plt-thunk.s4
-rw-r--r--test/ELF/arm-combined-dynrel-ifunc.s49
-rw-r--r--test/ELF/arm-extreme-range-pi-thunk.s82
-rw-r--r--test/ELF/arm-long-thunk-converge.s2
-rw-r--r--test/ELF/arm-thumb-branch-rangethunk.s4
-rw-r--r--test/ELF/arm-thumb-branch.s4
-rw-r--r--test/ELF/arm-thumb-condbranch-thunk.s2
-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-v5.s66
-rw-r--r--test/ELF/arm-thumb-interwork-thunk.s2
-rw-r--r--test/ELF/arm-thumb-mix-range-thunk-os.s2
-rw-r--r--test/ELF/arm-thumb-plt-range-thunk-os.s2
-rw-r--r--test/ELF/arm-thumb-range-thunk-os.s2
-rw-r--r--test/ELF/arm-thumb-thunk-empty-pass.s2
-rw-r--r--test/ELF/arm-thumb-thunk-symbols.s2
-rw-r--r--test/ELF/arm-thumb-thunk-v6m.s61
-rw-r--r--test/ELF/arm-thumb-undefined-weak-narrow.test50
-rw-r--r--test/ELF/arm-thunk-edgecase.s2
-rw-r--r--test/ELF/arm-thunk-largesection.s11
-rw-r--r--test/ELF/arm-thunk-linkerscript-dotexpr.s2
-rw-r--r--test/ELF/arm-thunk-linkerscript-large.s5
-rw-r--r--test/ELF/arm-thunk-linkerscript-orphan.s2
-rw-r--r--test/ELF/arm-thunk-linkerscript-sort.s2
-rw-r--r--test/ELF/arm-thunk-linkerscript.s2
-rw-r--r--test/ELF/arm-thunk-multipass.s2
-rw-r--r--test/ELF/arm-thunk-nosuitable.s5
-rw-r--r--test/ELF/arm-thunk-re-add.s2
-rw-r--r--test/ELF/arm-thunk-section-too-large.s2
-rw-r--r--test/ELF/arm-tls-le32.s12
-rw-r--r--test/ELF/arm-tls-norelax-ie-le.s4
-rw-r--r--test/ELF/arm-v4bx.test40
-rw-r--r--test/ELF/arm-v5-reloc-error.s31
-rw-r--r--test/ELF/as-needed-in-regular.s24
-rw-r--r--test/ELF/as-needed-not-in-regular.s32
-rw-r--r--test/ELF/as-needed-weak.s2
-rw-r--r--test/ELF/bad-reloc-target.test29
-rw-r--r--test/ELF/basic-aarch64.s16
-rw-r--r--test/ELF/basic-ppc64.s51
-rw-r--r--test/ELF/basic32.s16
-rw-r--r--test/ELF/basic64be.s65
-rw-r--r--test/ELF/bsymbolic-undef.s4
-rw-r--r--test/ELF/cgprofile-obj.s44
-rw-r--r--test/ELF/cgprofile-shared-warn.s21
-rw-r--r--test/ELF/cgprofile-txt2.s38
-rw-r--r--test/ELF/common-gc2.s4
-rw-r--r--test/ELF/compressed-debug-input-err.s4
-rw-r--r--test/ELF/conflict.s1
-rw-r--r--test/ELF/copy-rel-tls.s15
-rw-r--r--test/ELF/debug-line-str.s136
-rw-r--r--test/ELF/debug-relocation-none.test58
-rw-r--r--test/ELF/defsym.s19
-rw-r--r--test/ELF/dont-export-hidden.s2
-rw-r--r--test/ELF/driver-access.test2
-rw-r--r--test/ELF/driver.test3
-rw-r--r--test/ELF/dt_flags.s5
-rw-r--r--test/ELF/dynamic-list-locals.s7
-rw-r--r--test/ELF/dynamic-list-preempt.s8
-rw-r--r--test/ELF/dynamic-list-unexpected-end.s7
-rw-r--r--test/ELF/dynamic-list-wildcard.s6
-rw-r--r--test/ELF/dynamic-list.s22
-rw-r--r--test/ELF/dynamic-reloc.s2
-rw-r--r--test/ELF/dynsym-no-rosegment.s4
-rw-r--r--test/ELF/dynsym-pie.s2
-rw-r--r--test/ELF/edata-etext.s1
-rw-r--r--test/ELF/emit-relocs-icf1.s32
-rw-r--r--test/ELF/emit-relocs-icf2.s36
-rw-r--r--test/ELF/empty-pack-dyn-relocs.s11
-rw-r--r--test/ELF/empty-ver.s2
-rw-r--r--test/ELF/empty-ver2.s4
-rw-r--r--test/ELF/emulation-aarch64.s34
-rw-r--r--test/ELF/emulation-arm.s27
-rw-r--r--test/ELF/emulation-mips.s189
-rw-r--r--test/ELF/emulation-ppc.s75
-rw-r--r--test/ELF/emulation-x86.s205
-rw-r--r--test/ELF/emulation.s396
-rw-r--r--test/ELF/execute-only-mixed-data.s2
-rw-r--r--test/ELF/format-binary.test12
-rw-r--r--test/ELF/gc-sections-implicit-addend.s6
-rw-r--r--test/ELF/gc-sections-linker-defined-symbol.s2
-rw-r--r--test/ELF/gdb-index-base-addr.s2
-rw-r--r--test/ELF/gdb-index-dwarf5-low-high.s49
-rw-r--r--test/ELF/gdb-index-invalid-ranges.s42
-rw-r--r--test/ELF/gdb-index-multiple-cu-2.s36
-rw-r--r--test/ELF/gdb-index-multiple-cu.s88
-rw-r--r--test/ELF/gdb-index-no-debug.s8
-rw-r--r--test/ELF/gdb-index-ranges.s2
-rw-r--r--test/ELF/gdb-index-rng-lists.s202
-rw-r--r--test/ELF/gdb-index.s2
-rw-r--r--test/ELF/global-offset-table-position-redef-err.s14
-rw-r--r--test/ELF/gnu-hash-table-copy.s8
-rw-r--r--test/ELF/gnu-hash-table-rwsegment.s4
-rw-r--r--test/ELF/gnu-hash-table.s54
-rw-r--r--test/ELF/gnu-ifunc-empty.s16
-rw-r--r--test/ELF/gnu-ifunc-i386.s38
-rw-r--r--test/ELF/gnu-ifunc-plt-i386.s64
-rw-r--r--test/ELF/gnu-ifunc-plt.s8
-rw-r--r--test/ELF/gnu-ifunc-relative.s16
-rw-r--r--test/ELF/gnu-ifunc-shared.s6
-rw-r--r--test/ELF/gnu-ifunc.s4
-rw-r--r--test/ELF/gnu-unique.s4
-rw-r--r--test/ELF/got-i386.s18
-rw-r--r--test/ELF/got32-i386-pie-rw.s2
-rw-r--r--test/ELF/got32-i386.s4
-rw-r--r--test/ELF/got32x-i386.s10
-rw-r--r--test/ELF/hexagon-eflag.s7
-rw-r--r--test/ELF/hexagon-shared.s46
-rw-r--r--test/ELF/hexagon.s206
-rw-r--r--test/ELF/i386-linkonce.s9
-rw-r--r--test/ELF/i386-pc8-pc16-addend.s8
-rw-r--r--test/ELF/i386-retpoline-nopic.s96
-rw-r--r--test/ELF/icf13.s1
-rw-r--r--test/ELF/icf15.s1
-rw-r--r--test/ELF/icf16.s1
-rw-r--r--test/ELF/icf17.s1
-rw-r--r--test/ELF/image-base.s3
-rw-r--r--test/ELF/incompatible-ar-first.s1
-rw-r--r--test/ELF/incompatible.s1
-rw-r--r--test/ELF/invalid-linkerscript.test8
-rw-r--r--test/ELF/invalid/Inputs/shentsize-zero.elfbin512 -> 0 bytes
-rw-r--r--test/ELF/invalid/Inputs/sht-group.elfbin480 -> 0 bytes
-rwxr-xr-xtest/ELF/invalid/Inputs/undefined-local-symbol-in-dso.sobin0 -> 5080 bytes
-rw-r--r--test/ELF/invalid/comdat-broken.test25
-rw-r--r--test/ELF/invalid/ehframe-broken-relocation.test31
-rw-r--r--test/ELF/invalid/invalid-soname.test18
-rw-r--r--test/ELF/invalid/linkorder-invalid-sec.test16
-rw-r--r--test/ELF/invalid/linkorder-invalid-sec2.test16
-rw-r--r--test/ELF/invalid/merge-invalid-size.s3
-rw-r--r--test/ELF/invalid/merge-zero-size.test21
-rw-r--r--test/ELF/invalid/non-terminated-string.test19
-rw-r--r--test/ELF/invalid/sht-group-wrong-section.test22
-rw-r--r--test/ELF/invalid/sht-group.s3
-rw-r--r--test/ELF/invalid/sht-group.test18
-rw-r--r--test/ELF/invalid/undefined-local-symbol-in-dso.test66
-rw-r--r--test/ELF/lazy-arch-conflict.s7
-rw-r--r--test/ELF/linkerscript/Inputs/at6.s11
-rw-r--r--test/ELF/linkerscript/Inputs/at7.s7
-rw-r--r--test/ELF/linkerscript/Inputs/at8.s8
-rw-r--r--test/ELF/linkerscript/align-r.test2
-rw-r--r--test/ELF/linkerscript/align4.test1
-rw-r--r--test/ELF/linkerscript/at6.test30
-rw-r--r--test/ELF/linkerscript/at7.test28
-rw-r--r--test/ELF/linkerscript/at8.test31
-rw-r--r--test/ELF/linkerscript/discard-section-err.s20
-rw-r--r--test/ELF/linkerscript/filename-spec.s1
-rw-r--r--test/ELF/linkerscript/icf.s11
-rw-r--r--test/ELF/linkerscript/info-section-type.s9
-rw-r--r--test/ELF/linkerscript/lazy-symbols.test1
-rw-r--r--test/ELF/linkerscript/map-file.test8
-rw-r--r--test/ELF/linkerscript/map-file2.test22
-rw-r--r--test/ELF/linkerscript/memory-include.test23
-rw-r--r--test/ELF/linkerscript/merge-nonalloc.s14
-rw-r--r--test/ELF/linkerscript/no-filename-spec.s17
-rw-r--r--test/ELF/linkerscript/non-alloc-segment.s2
-rw-r--r--test/ELF/linkerscript/non-alloc.s2
-rw-r--r--test/ELF/linkerscript/orphan-discard.s2
-rw-r--r--test/ELF/linkerscript/orphan-phdrs.s2
-rw-r--r--test/ELF/linkerscript/ouputformat.s9
-rw-r--r--test/ELF/linkerscript/output-section-include.test30
-rw-r--r--test/ELF/linkerscript/output-too-large.s6
-rw-r--r--test/ELF/linkerscript/phdrs.s8
-rw-r--r--test/ELF/linkerscript/provide-shared2.s2
-rw-r--r--test/ELF/linkerscript/relocatable-discard.s21
-rw-r--r--test/ELF/linkerscript/section-include.test32
-rw-r--r--test/ELF/linkerscript/sections-va-overflow.test4
-rw-r--r--test/ELF/linkerscript/segment-none.s4
-rw-r--r--test/ELF/linkerscript/sizeof.s1
-rw-r--r--test/ELF/linkerscript/sizeofheaders.s1
-rw-r--r--test/ELF/linkerscript/sort-init.s6
-rw-r--r--test/ELF/linkerscript/sort-non-script.s2
-rw-r--r--test/ELF/linkerscript/symbol-assignexpr.s1
-rw-r--r--test/ELF/linkerscript/symbol-location.s15
-rw-r--r--test/ELF/linkerscript/symbol-memoryexpr.s1
-rw-r--r--test/ELF/linkerscript/target.s18
-rw-r--r--test/ELF/linkerscript/unused-synthetic.s2
-rw-r--r--test/ELF/linkerscript/version-script.s6
-rw-r--r--test/ELF/local-dynamic.s4
-rw-r--r--test/ELF/local-ver-preemptible.s22
-rw-r--r--test/ELF/lto-plugin-ignore.s4
-rw-r--r--test/ELF/lto/Inputs/libcall-archive.s2
-rw-r--r--test/ELF/lto/amdgcn.ll12
-rw-r--r--test/ELF/lto/cache.ll22
-rw-r--r--test/ELF/lto/data-ordering-lto.s2
-rw-r--r--test/ELF/lto/defsym.ll4
-rw-r--r--test/ELF/lto/dynamic-list.ll2
-rw-r--r--test/ELF/lto/emit-llvm.ll14
-rw-r--r--test/ELF/lto/libcall-archive.ll7
-rw-r--r--test/ELF/lto/ltopasses-custom.ll4
-rw-r--r--test/ELF/lto/opt-remarks.ll10
-rw-r--r--test/ELF/lto/ppc64le.ll12
-rw-r--r--test/ELF/lto/r600.ll12
-rw-r--r--test/ELF/lto/relocatable.ll9
-rw-r--r--test/ELF/lto/section-name.ll4
-rw-r--r--test/ELF/lto/shlib-undefined.ll2
-rw-r--r--test/ELF/lto/symbol-ordering-lto.s2
-rw-r--r--test/ELF/lto/thinlto-obj-path.ll3
-rw-r--r--test/ELF/lto/thinlto-object-suffix-replace.ll12
-rw-r--r--test/ELF/lto/undefined-puts.ll2
-rw-r--r--test/ELF/lto/version-script.ll2
-rw-r--r--test/ELF/lto/wrap-2.ll8
-rw-r--r--test/ELF/map-file-i686.s24
-rw-r--r--test/ELF/merge-string-error.s2
-rw-r--r--test/ELF/mergeable-errors.s8
-rw-r--r--test/ELF/mips-32.s4
-rw-r--r--test/ELF/mips-64.s4
-rw-r--r--test/ELF/mips-dynamic.s6
-rw-r--r--test/ELF/mips-dynsym-sort.s6
-rw-r--r--test/ELF/mips-gnu-hash.s2
-rw-r--r--test/ELF/mips-got-and-copy.s4
-rw-r--r--test/ELF/mips-got-extsym.s2
-rw-r--r--test/ELF/mips-got-relocs.s4
-rw-r--r--test/ELF/mips-got16-relocatable.s8
-rw-r--r--test/ELF/mips-got16.s2
-rw-r--r--test/ELF/mips-hilo.s6
-rw-r--r--test/ELF/mips-mgot.s14
-rw-r--r--test/ELF/mips-micro-jal.s12
-rw-r--r--test/ELF/mips-micro-plt.s2
-rw-r--r--test/ELF/mips-npic-call-pic-os.s35
-rw-r--r--test/ELF/mips-npic-call-pic-script.s114
-rw-r--r--test/ELF/mips-npic-call-pic.s25
-rw-r--r--test/ELF/mips-sto-plt.s4
-rw-r--r--test/ELF/mips-tls-64.s6
-rw-r--r--test/ELF/mips-tls-hilo.s2
-rw-r--r--test/ELF/mips-tls-static-64.s4
-rw-r--r--test/ELF/mips-tls-static.s4
-rw-r--r--test/ELF/mips-tls.s6
-rw-r--r--test/ELF/mips-traps.s22
-rw-r--r--test/ELF/msp430.s43
-rw-r--r--test/ELF/no-obj.s1
-rw-r--r--test/ELF/note-first-page.s12
-rw-r--r--test/ELF/oformat-binary.s1
-rw-r--r--test/ELF/pack-dyn-relocs-loop.s66
-rw-r--r--test/ELF/pack-dyn-relocs-tls-aarch64.s34
-rw-r--r--test/ELF/pack-dyn-relocs-tls-x86-64.s23
-rw-r--r--test/ELF/plt-aarch64.s82
-rw-r--r--test/ELF/plt-i686.s68
-rw-r--r--test/ELF/plt.s10
-rw-r--r--test/ELF/ppc-relocs.s17
-rw-r--r--test/ELF/ppc64-bsymbolic-toc-restore.s68
-rw-r--r--test/ELF/ppc64-call-reach.s94
-rw-r--r--test/ELF/ppc64-dq.s32
-rw-r--r--test/ELF/ppc64-dtprel.s8
-rw-r--r--test/ELF/ppc64-entry-point.s (renamed from test/ELF/ppc64_entry_point.s)15
-rw-r--r--test/ELF/ppc64-error-missaligned-dq.s26
-rw-r--r--test/ELF/ppc64-error-missaligned-ds.s26
-rw-r--r--test/ELF/ppc64-func-entry-points.s2
-rw-r--r--test/ELF/ppc64-gd-to-ie.s8
-rw-r--r--test/ELF/ppc64-general-dynamic-tls.s12
-rw-r--r--test/ELF/ppc64-got-indirect.s4
-rw-r--r--test/ELF/ppc64-got-off.s67
-rw-r--r--test/ELF/ppc64-initial-exec-tls.s12
-rw-r--r--test/ELF/ppc64-local-dynamic.s12
-rw-r--r--test/ELF/ppc64-local-exec-tls.s4
-rw-r--r--test/ELF/ppc64-long-branch.s121
-rw-r--r--test/ELF/ppc64-rel-so-local-calls.s4
-rw-r--r--test/ELF/ppc64-relocs.s49
-rw-r--r--test/ELF/ppc64-shared-long_branch.s114
-rw-r--r--test/ELF/ppc64-split-stack-adjust-fail.s53
-rw-r--r--test/ELF/ppc64-split-stack-adjust-overflow.s64
-rw-r--r--test/ELF/ppc64-split-stack-adjust-size-success.s108
-rw-r--r--test/ELF/ppc64-split-stack-prologue-adjust-success.s224
-rw-r--r--test/ELF/ppc64-tls-gd-le-small.s61
-rw-r--r--test/ELF/ppc64-tls-gd-le.s12
-rw-r--r--test/ELF/ppc64-tls-ie-le.s140
-rw-r--r--test/ELF/ppc64-tls-ld-le.s12
-rw-r--r--test/ELF/ppc64-toc-addis-nop-lqsq.s73
-rw-r--r--test/ELF/ppc64-toc-addis-nop.s272
-rw-r--r--test/ELF/ppc64-toc-rel.s30
-rw-r--r--test/ELF/ppc64-toc-restore-recursive-call.s52
-rw-r--r--test/ELF/ppc64-toc-restore.s2
-rw-r--r--test/ELF/ppc64-tocopt-option.s14
-rw-r--r--test/ELF/pr34660.s2
-rw-r--r--test/ELF/progname.s2
-rw-r--r--test/ELF/protected-shared.s4
-rw-r--r--test/ELF/push-state.s3
-rw-r--r--test/ELF/relative-dynamic-reloc-ppc64.s4
-rw-r--r--test/ELF/relative-dynamic-reloc.s4
-rw-r--r--test/ELF/relocatable-bss.s2
-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-compressed-input.s2
-rw-r--r--test/ELF/relocatable-many-sections.s18
-rw-r--r--test/ELF/relocatable-rel-iplt.s56
-rw-r--r--test/ELF/relocatable.s16
-rw-r--r--test/ELF/relocation-b-aarch64.test4
-rw-r--r--test/ELF/relocation-before-merge-start.s9
-rw-r--r--test/ELF/relocation-common.s12
-rw-r--r--test/ELF/relocation-copy-i686.s14
-rw-r--r--test/ELF/relocation-i686.s30
-rw-r--r--test/ELF/relocation-past-merge-end.s2
-rw-r--r--test/ELF/relocation-size-shared.s15
-rw-r--r--test/ELF/relocation-size.s13
-rw-r--r--test/ELF/reproduce-backslash.s2
-rw-r--r--test/ELF/retain-symbols-file.s2
-rw-r--r--test/ELF/riscv-branch.test119
-rw-r--r--test/ELF/riscv-call.test95
-rw-r--r--test/ELF/riscv-hi20-lo12.test86
-rw-r--r--test/ELF/riscv-jal-error.test93
-rw-r--r--test/ELF/riscv-jal.test161
-rw-r--r--test/ELF/riscv-pcrel-hilo.test103
-rw-r--r--test/ELF/shared.s20
-rw-r--r--test/ELF/sort-norosegment.s2
-rw-r--r--test/ELF/static-error.s13
-rw-r--r--test/ELF/static-with-export-dynamic.s2
-rw-r--r--test/ELF/strip-debug.s4
-rw-r--r--test/ELF/symbol-ordering-file-warnings.s13
-rw-r--r--test/ELF/textrel.s40
-rw-r--r--test/ELF/tls-i686.s20
-rw-r--r--test/ELF/tls-in-archive.s1
-rw-r--r--test/ELF/tls-opt-gdiele-i686.s20
-rw-r--r--test/ELF/tls-opt-i686.s32
-rw-r--r--test/ELF/tls-opt-iele-i686-nopic.s42
-rw-r--r--test/ELF/tls-static.s1
-rw-r--r--test/ELF/tls-weak-undef.s1
-rw-r--r--test/ELF/trace-ar.s1
-rw-r--r--test/ELF/trace-symbols.s2
-rw-r--r--test/ELF/undef-broken-debug.test2
-rw-r--r--test/ELF/undef-version-script.s6
-rw-r--r--test/ELF/undef-with-plt-addr-i686.s4
-rw-r--r--test/ELF/undef.s5
-rw-r--r--test/ELF/verdef-defaultver.s8
-rw-r--r--test/ELF/verdef.s4
-rw-r--r--test/ELF/verneed.s4
-rw-r--r--test/ELF/version-exclude-libs.s1
-rw-r--r--test/ELF/version-script-complex-wildcards.s8
-rw-r--r--test/ELF/version-script-extern-undefined.s4
-rw-r--r--test/ELF/version-script-extern-wildcards.s2
-rw-r--r--test/ELF/version-script-extern.s4
-rw-r--r--test/ELF/version-script-extern2.s2
-rw-r--r--test/ELF/version-script-hide-so-symbol.s2
-rw-r--r--test/ELF/version-script-locals-extern.s8
-rw-r--r--test/ELF/version-script-symver2.s2
-rw-r--r--test/ELF/version-script-weak.s2
-rw-r--r--test/ELF/version-script.s28
-rw-r--r--test/ELF/version-wildcard.test4
-rw-r--r--test/ELF/visibility.s2
-rw-r--r--test/ELF/weak-undef-export.s4
-rw-r--r--test/ELF/weak-undef.s4
-rw-r--r--test/ELF/wrap-entry.s13
-rw-r--r--test/ELF/wrap-no-real.s58
-rw-r--r--test/ELF/wrap-plt.s45
-rw-r--r--test/ELF/wrap-with-archive.s13
-rw-r--r--test/ELF/wrap.s2
-rw-r--r--test/ELF/x86-64-combined-dynrel.s40
-rw-r--r--test/ELF/x86-64-reloc-error2.s12
-rw-r--r--test/ELF/x86-64-reloc-gotoff64.s2
-rw-r--r--test/ELF/x86-64-reloc-gotpc64.s2
-rw-r--r--test/ELF/x86-64-reloc-range-debug-loc.s2
-rw-r--r--test/ELF/x86-64-reloc-range.s2
-rw-r--r--test/ELF/x86-64-retpoline-znow-static-iplt.s26
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-fail.s12
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-shared.s31
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-silent.s2
-rw-r--r--test/ELF/x86-64-split-stack-prologue-adjust-success.s35
-rw-r--r--test/ELF/znotext-plt-relocations-protected.s7
-rw-r--r--test/ELF/zstack-size.s3
-rw-r--r--test/MinGW/driver.test6
-rw-r--r--test/lit.cfg.py18
-rw-r--r--test/lit.site.cfg.py.in3
-rw-r--r--test/mach-o/cstring-sections.yaml8
-rw-r--r--test/mach-o/dependency_info.yaml2
-rw-r--r--test/mach-o/parse-data-relocs-x86_64.yaml2
-rw-r--r--test/mach-o/parse-data.yaml2
-rw-r--r--test/mach-o/sectcreate.yaml2
-rw-r--r--test/wasm/Inputs/event-section1.ll9
-rw-r--r--test/wasm/Inputs/event-section2.ll9
-rw-r--r--test/wasm/Inputs/globals.yaml2
-rw-r--r--test/wasm/Inputs/undefined-globals.yaml2
-rw-r--r--test/wasm/alias.ll4
-rw-r--r--test/wasm/archive-export.ll50
-rw-r--r--test/wasm/archive.ll1
-rw-r--r--test/wasm/call-indirect.ll10
-rw-r--r--test/wasm/comdats.ll2
-rw-r--r--test/wasm/compress-relocs.ll10
-rw-r--r--test/wasm/cxx-mangling.ll20
-rw-r--r--test/wasm/data-layout.ll10
-rw-r--r--test/wasm/data-segment-merging.ll51
-rw-r--r--test/wasm/debug-removed-fn.ll44
-rw-r--r--test/wasm/debuginfo.test4
-rw-r--r--test/wasm/demangle.ll14
-rw-r--r--test/wasm/event-section.ll34
-rw-r--r--test/wasm/export-all.ll2
-rw-r--r--test/wasm/export-table.test2
-rw-r--r--test/wasm/export.ll6
-rw-r--r--test/wasm/import-memory.test17
-rw-r--r--test/wasm/import-table.test4
-rw-r--r--test/wasm/load-undefined.test14
-rw-r--r--test/wasm/local-symbols.ll5
-rw-r--r--test/wasm/locals-duplicate.test14
-rw-r--r--test/wasm/lto/archive.ll2
-rw-r--r--test/wasm/lto/cache.ll8
-rw-r--r--test/wasm/lto/export.ll6
-rw-r--r--test/wasm/lto/signature-mismatch.ll19
-rw-r--r--test/wasm/many-functions.ll6
-rw-r--r--test/wasm/relocatable.ll16
-rw-r--r--test/wasm/shared.ll82
-rw-r--r--test/wasm/signature-mismatch-weak.ll4
-rw-r--r--test/wasm/signature-mismatch.ll8
-rw-r--r--test/wasm/stack-pointer.ll4
-rw-r--r--test/wasm/strip-all.test10
-rw-r--r--test/wasm/strip-debug.test4
-rw-r--r--test/wasm/undefined-entry.test8
-rw-r--r--test/wasm/undefined-weak-call.ll4
-rw-r--r--test/wasm/undefined.ll4
-rw-r--r--test/wasm/visibility-hidden.ll36
-rw-r--r--test/wasm/weak-alias-overide.ll10
-rw-r--r--test/wasm/weak-alias.ll8
-rw-r--r--test/wasm/weak-symbols.ll17
-rw-r--r--test/wasm/weak-undefined.ll13
-rw-r--r--tools/lld/lld.cpp2
-rw-r--r--wasm/Config.h9
-rw-r--r--wasm/Driver.cpp288
-rw-r--r--wasm/InputChunks.cpp27
-rw-r--r--wasm/InputChunks.h40
-rw-r--r--wasm/InputEvent.h63
-rw-r--r--wasm/InputFiles.cpp93
-rw-r--r--wasm/InputFiles.h22
-rw-r--r--wasm/InputGlobal.h3
-rw-r--r--wasm/LTO.cpp17
-rw-r--r--wasm/MarkLive.cpp6
-rw-r--r--wasm/Options.td49
-rw-r--r--wasm/OutputSections.cpp16
-rw-r--r--wasm/OutputSections.h8
-rw-r--r--wasm/OutputSegment.h2
-rw-r--r--wasm/SymbolTable.cpp147
-rw-r--r--wasm/SymbolTable.h11
-rw-r--r--wasm/Symbols.cpp52
-rw-r--r--wasm/Symbols.h93
-rw-r--r--wasm/Writer.cpp190
-rw-r--r--wasm/WriterUtils.cpp82
-rw-r--r--wasm/WriterUtils.h13
711 files changed, 19884 insertions, 5608 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 412ff783222b..29131d7eb8db 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -11,6 +11,7 @@
#include "InputFiles.h"
#include "Symbols.h"
#include "Writer.h"
+#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
@@ -44,6 +45,22 @@ SectionChunk::SectionChunk(ObjFile *F, const coff_section *H)
Live = !Config->DoGC || !isCOMDAT();
}
+// Initialize the RelocTargets vector, to allow redirecting certain relocations
+// to a thunk instead of the actual symbol the relocation's symbol table index
+// indicates.
+void SectionChunk::readRelocTargets() {
+ assert(RelocTargets.empty());
+ RelocTargets.reserve(Relocs.size());
+ for (const coff_relocation &Rel : Relocs)
+ RelocTargets.push_back(File->getSymbol(Rel.SymbolTableIndex));
+}
+
+// Reset RelocTargets to their original targets before thunks were added.
+void SectionChunk::resetRelocTargets() {
+ for (size_t I = 0, E = Relocs.size(); I < E; ++I)
+ RelocTargets[I] = File->getSymbol(Relocs[I].SymbolTableIndex);
+}
+
static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); }
static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); }
static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); }
@@ -58,7 +75,8 @@ static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) {
return true;
if (Sec->isCodeView())
return false;
- fatal("SECREL relocation cannot be applied to absolute symbols");
+ error("SECREL relocation cannot be applied to absolute symbols");
+ return false;
}
static void applySecRel(const SectionChunk *Sec, uint8_t *Off,
@@ -98,7 +116,7 @@ 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) + " in " +
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
toString(File));
}
}
@@ -113,7 +131,7 @@ 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) + " in " +
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
toString(File));
}
}
@@ -123,16 +141,22 @@ static void applyMOV(uint8_t *Off, uint16_t V) {
write16le(Off + 2, (read16le(Off + 2) & 0x8f00) | ((V & 0x700) << 4) | (V & 0xff));
}
-static uint16_t readMOV(uint8_t *Off) {
+static uint16_t readMOV(uint8_t *Off, bool MOVT) {
uint16_t Op1 = read16le(Off);
+ if ((Op1 & 0xfbf0) != (MOVT ? 0xf2c0 : 0xf240))
+ error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+ " instruction in MOV32T relocation");
uint16_t Op2 = read16le(Off + 2);
+ if ((Op2 & 0x8000) != 0)
+ error("unexpected instruction in " + Twine(MOVT ? "MOVT" : "MOVW") +
+ " instruction in MOV32T relocation");
return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) |
((Op1 & 0x000f) << 12);
}
void applyMOV32T(uint8_t *Off, uint32_t V) {
- uint16_t ImmW = readMOV(Off); // read MOVW operand
- uint16_t ImmT = readMOV(Off + 4); // read MOVT operand
+ uint16_t ImmW = readMOV(Off, false); // read MOVW operand
+ uint16_t ImmT = readMOV(Off + 4, true); // read MOVT operand
uint32_t Imm = ImmW | (ImmT << 16);
V += Imm; // add the immediate offset
applyMOV(Off, V); // set MOVW operand
@@ -141,7 +165,7 @@ void applyMOV32T(uint8_t *Off, uint32_t V) {
static void applyBranch20T(uint8_t *Off, int32_t V) {
if (!isInt<21>(V))
- fatal("relocation out of range");
+ error("relocation out of range");
uint32_t S = V < 0 ? 1 : 0;
uint32_t J1 = (V >> 19) & 1;
uint32_t J2 = (V >> 18) & 1;
@@ -151,7 +175,7 @@ static void applyBranch20T(uint8_t *Off, int32_t V) {
void applyBranch24T(uint8_t *Off, int32_t V) {
if (!isInt<25>(V))
- fatal("relocation out of range");
+ error("relocation out of range");
uint32_t S = V < 0 ? 1 : 0;
uint32_t J1 = ((~V >> 23) & 1) ^ S;
uint32_t J2 = ((~V >> 22) & 1) ^ S;
@@ -176,7 +200,7 @@ 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) + " in " +
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
toString(File));
}
}
@@ -184,7 +208,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
// 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, int Shift) {
+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;
@@ -198,7 +222,7 @@ static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
// Update the immediate field in a AARCH64 ldr, str, and add instruction.
// Optionally limit the range of the written immediate by one or more bits
// (RangeLimit).
-static void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit) {
uint32_t Orig = read32le(Off);
Imm += (Orig >> 10) & 0xFFF;
Orig &= ~(0xFFF << 10);
@@ -221,7 +245,7 @@ static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) {
if ((Orig & 0x4800000) == 0x4800000)
Size += 4;
if ((Imm & ((1 << Size) - 1)) != 0)
- fatal("misaligned ldr/str offset");
+ error("misaligned ldr/str offset");
applyArm64Imm(Off, Imm >> Size, Size);
}
@@ -250,21 +274,21 @@ static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
}
-static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+void applyArm64Branch26(uint8_t *Off, int64_t V) {
if (!isInt<28>(V))
- fatal("relocation out of range");
+ error("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");
+ error("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");
+ error("relocation out of range");
or32(Off, (V & 0x0000FFFC) << 3);
}
@@ -287,11 +311,37 @@ void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
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) + " in " +
+ error("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " +
toString(File));
}
}
+static void maybeReportRelocationToDiscarded(const SectionChunk *FromChunk,
+ Defined *Sym,
+ const coff_relocation &Rel) {
+ // Don't report these errors when the relocation comes from a debug info
+ // section or in mingw mode. MinGW mode object files (built by GCC) can
+ // have leftover sections with relocations against discarded comdat
+ // sections. Such sections are left as is, with relocations untouched.
+ if (FromChunk->isCodeView() || FromChunk->isDWARF() || Config->MinGW)
+ return;
+
+ // Get the name of the symbol. If it's null, it was discarded early, so we
+ // have to go back to the object file.
+ ObjFile *File = FromChunk->File;
+ StringRef Name;
+ if (Sym) {
+ Name = Sym->getName();
+ } else {
+ COFFSymbolRef COFFSym =
+ check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex));
+ File->getCOFFObj()->getSymbolName(COFFSym, Name);
+ }
+
+ error("relocation against symbol in discarded section: " + Name +
+ getSymbolLocations(File, Rel.SymbolTableIndex));
+}
+
void SectionChunk::writeTo(uint8_t *Buf) const {
if (!hasData())
return;
@@ -302,46 +352,40 @@ void SectionChunk::writeTo(uint8_t *Buf) const {
// Apply relocations.
size_t InputSize = getSize();
- for (const coff_relocation &Rel : Relocs) {
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
+
// Check for an invalid relocation offset. This check isn't perfect, because
// we don't have the relocation size, which is only known after checking the
// machine and relocation type. As a result, a relocation may overwrite the
// beginning of the following input section.
- if (Rel.VirtualAddress >= InputSize)
- fatal("relocation points beyond the end of its parent section");
+ if (Rel.VirtualAddress >= InputSize) {
+ error("relocation points beyond the end of its parent section");
+ continue;
+ }
uint8_t *Off = Buf + OutputSectionOff + Rel.VirtualAddress;
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ auto *Sym = dyn_cast_or_null<Defined>(RelocTargets[I]);
+
// Get the output section of the symbol for this relocation. The output
// section is needed to compute SECREL and SECTION relocations used in debug
// info.
- auto *Sym =
- dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
- if (!Sym) {
- if (isCodeView() || isDWARF())
- continue;
- // Symbols in early discarded sections are represented using null pointers,
- // so we need to retrieve the name from the object file.
- COFFSymbolRef Sym =
- check(File->getCOFFObj()->getSymbol(Rel.SymbolTableIndex));
- StringRef Name;
- File->getCOFFObj()->getSymbolName(Sym, Name);
- fatal("relocation against symbol in discarded section: " + Name);
- }
- Chunk *C = Sym->getChunk();
+ Chunk *C = Sym ? Sym->getChunk() : nullptr;
OutputSection *OS = C ? C->getOutputSection() : nullptr;
- // Only absolute and __ImageBase symbols lack an output section. For any
- // other symbol, this indicates that the chunk was discarded. Normally
- // relocations against discarded sections are an error. However, debug info
- // sections are not GC roots and can end up with these kinds of relocations.
- // Skip these relocations.
- if (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym)) {
- if (isCodeView() || isDWARF())
- continue;
- fatal("relocation against symbol in discarded section: " +
- Sym->getName());
+ // Skip the relocation if it refers to a discarded section, and diagnose it
+ // as an error if appropriate. If a symbol was discarded early, it may be
+ // null. If it was discarded late, the output section will be null, unless
+ // it was an absolute or synthetic symbol.
+ if (!Sym ||
+ (!OS && !isa<DefinedAbsolute>(Sym) && !isa<DefinedSynthetic>(Sym))) {
+ maybeReportRelocationToDiscarded(this, Sym, Rel);
+ continue;
}
+
uint64_t S = Sym->getRVA();
// Compute the RVA of the relocation for relative relocations.
@@ -399,17 +443,125 @@ static uint8_t getBaserelType(const coff_relocation &Rel) {
// fixed by the loader if load-time relocation is needed.
// Only called when base relocation is enabled.
void SectionChunk::getBaserels(std::vector<Baserel> *Res) {
- for (const coff_relocation &Rel : Relocs) {
+ for (size_t I = 0, E = Relocs.size(); I < E; I++) {
+ const coff_relocation &Rel = Relocs[I];
uint8_t Ty = getBaserelType(Rel);
if (Ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
- Symbol *Target = File->getSymbol(Rel.SymbolTableIndex);
+ // Use the potentially remapped Symbol instead of the one that the
+ // relocation points to.
+ Symbol *Target = RelocTargets[I];
if (!Target || isa<DefinedAbsolute>(Target))
continue;
Res->emplace_back(RVA + Rel.VirtualAddress, Ty);
}
}
+// MinGW specific.
+// Check whether a static relocation of type Type can be deferred and
+// handled at runtime as a pseudo relocation (for references to a module
+// local variable, which turned out to actually need to be imported from
+// another DLL) This returns the size the relocation is supposed to update,
+// in bits, or 0 if the relocation cannot be handled as a runtime pseudo
+// relocation.
+static int getRuntimePseudoRelocSize(uint16_t Type) {
+ // Relocations that either contain an absolute address, or a plain
+ // relative offset, since the runtime pseudo reloc implementation
+ // adds 8/16/32/64 bit values to a memory address.
+ //
+ // Given a pseudo relocation entry,
+ //
+ // typedef struct {
+ // DWORD sym;
+ // DWORD target;
+ // DWORD flags;
+ // } runtime_pseudo_reloc_item_v2;
+ //
+ // the runtime relocation performs this adjustment:
+ // *(base + .target) += *(base + .sym) - (base + .sym)
+ //
+ // This works for both absolute addresses (IMAGE_REL_*_ADDR32/64,
+ // IMAGE_REL_I386_DIR32, where the memory location initially contains
+ // the address of the IAT slot, and for relative addresses (IMAGE_REL*_REL32),
+ // where the memory location originally contains the relative offset to the
+ // IAT slot.
+ //
+ // This requires the target address to be writable, either directly out of
+ // the image, or temporarily changed at runtime with VirtualProtect.
+ // Since this only operates on direct address values, it doesn't work for
+ // ARM/ARM64 relocations, other than the plain ADDR32/ADDR64 relocations.
+ switch (Config->Machine) {
+ case AMD64:
+ switch (Type) {
+ case IMAGE_REL_AMD64_ADDR64:
+ return 64;
+ case IMAGE_REL_AMD64_ADDR32:
+ case IMAGE_REL_AMD64_REL32:
+ case IMAGE_REL_AMD64_REL32_1:
+ case IMAGE_REL_AMD64_REL32_2:
+ case IMAGE_REL_AMD64_REL32_3:
+ case IMAGE_REL_AMD64_REL32_4:
+ case IMAGE_REL_AMD64_REL32_5:
+ return 32;
+ default:
+ return 0;
+ }
+ case I386:
+ switch (Type) {
+ case IMAGE_REL_I386_DIR32:
+ case IMAGE_REL_I386_REL32:
+ return 32;
+ default:
+ return 0;
+ }
+ case ARMNT:
+ switch (Type) {
+ case IMAGE_REL_ARM_ADDR32:
+ return 32;
+ default:
+ return 0;
+ }
+ case ARM64:
+ switch (Type) {
+ case IMAGE_REL_ARM64_ADDR64:
+ return 64;
+ case IMAGE_REL_ARM64_ADDR32:
+ return 32;
+ default:
+ return 0;
+ }
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
+
+// MinGW specific.
+// Append information to the provided vector about all relocations that
+// need to be handled at runtime as runtime pseudo relocations (references
+// to a module local variable, which turned out to actually need to be
+// imported from another DLL).
+void SectionChunk::getRuntimePseudoRelocs(
+ std::vector<RuntimePseudoReloc> &Res) {
+ for (const coff_relocation &Rel : Relocs) {
+ auto *Target =
+ dyn_cast_or_null<Defined>(File->getSymbol(Rel.SymbolTableIndex));
+ if (!Target || !Target->IsRuntimePseudoReloc)
+ continue;
+ int SizeInBits = getRuntimePseudoRelocSize(Rel.Type);
+ if (SizeInBits == 0) {
+ error("unable to automatically import from " + Target->getName() +
+ " with relocation type " +
+ File->getCOFFObj()->getRelocationTypeName(Rel.Type) + " in " +
+ toString(File));
+ continue;
+ }
+ // SizeInBits is used to initialize the Flags field; currently no
+ // other flags are defined.
+ Res.emplace_back(
+ RuntimePseudoReloc(Target, this, Rel.VirtualAddress, SizeInBits));
+ }
+}
+
bool SectionChunk::hasData() const {
return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA);
}
@@ -447,6 +599,13 @@ void SectionChunk::replace(SectionChunk *Other) {
Other->Live = false;
}
+uint32_t SectionChunk::getSectionNumber() const {
+ DataRefImpl R;
+ R.p = reinterpret_cast<uintptr_t>(Header);
+ SectionRef S(R, File->getCOFFObj());
+ return S.getIndex() + 1;
+}
+
CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) {
// Common symbols are aligned on natural boundaries up to 32 bytes.
// This is what MSVC link.exe does.
@@ -460,6 +619,7 @@ uint32_t CommonChunk::getOutputCharacteristics() const {
void StringChunk::writeTo(uint8_t *Buf) const {
memcpy(Buf + OutputSectionOff, Str.data(), Str.size());
+ Buf[OutputSectionOff + Str.size()] = '\0';
}
ImportThunkChunkX64::ImportThunkChunkX64(Defined *S) : ImpSymbol(S) {
@@ -502,13 +662,30 @@ void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
+// A Thumb2, PIC, non-interworking range extension thunk.
+const uint8_t ArmThunk[] = {
+ 0x40, 0xf2, 0x00, 0x0c, // P: movw ip,:lower16:S - (P + (L1-P) + 4)
+ 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4)
+ 0xe7, 0x44, // L1: add pc, ip
+};
+
+size_t RangeExtensionThunk::getSize() const {
+ assert(Config->Machine == ARMNT);
+ return sizeof(ArmThunk);
+}
+
+void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARMNT);
+ uint64_t Offset = Target->getRVA() - RVA - 12;
+ memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
+ applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
Res->emplace_back(getRVA());
}
-size_t LocalImportChunk::getSize() const {
- return Config->is64() ? 8 : 4;
-}
+size_t LocalImportChunk::getSize() const { return Config->Wordsize; }
void LocalImportChunk::writeTo(uint8_t *Buf) const {
if (Config->is64()) {
@@ -528,6 +705,34 @@ void RVATableChunk::writeTo(uint8_t *Buf) const {
"RVA tables should be de-duplicated");
}
+// MinGW specific, for the "automatic import of variables from DLLs" feature.
+size_t PseudoRelocTableChunk::getSize() const {
+ if (Relocs.empty())
+ return 0;
+ return 12 + 12 * Relocs.size();
+}
+
+// MinGW specific.
+void PseudoRelocTableChunk::writeTo(uint8_t *Buf) const {
+ if (Relocs.empty())
+ return;
+
+ ulittle32_t *Table = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff);
+ // This is the list header, to signal the runtime pseudo relocation v2
+ // format.
+ Table[0] = 0;
+ Table[1] = 0;
+ Table[2] = 1;
+
+ size_t Idx = 3;
+ for (const RuntimePseudoReloc &RPR : Relocs) {
+ Table[Idx + 0] = RPR.Sym->getRVA();
+ Table[Idx + 1] = RPR.Target->getRVA() + RPR.TargetOffset;
+ Table[Idx + 2] = RPR.Flags;
+ Idx += 3;
+ }
+}
+
// Windows-specific. This class represents a block in .reloc section.
// The format is described here.
//
@@ -613,13 +818,16 @@ void MergeChunk::addSection(SectionChunk *C) {
}
void MergeChunk::finalizeContents() {
- for (SectionChunk *C : Sections)
- if (C->isLive())
- Builder.add(toStringRef(C->getContents()));
- Builder.finalize();
+ if (!Finalized) {
+ for (SectionChunk *C : Sections)
+ if (C->Live)
+ Builder.add(toStringRef(C->getContents()));
+ Builder.finalize();
+ Finalized = true;
+ }
for (SectionChunk *C : Sections) {
- if (!C->isLive())
+ if (!C->Live)
continue;
size_t Off = Builder.getOffset(toStringRef(C->getContents()));
C->setOutputSection(Out);
@@ -640,5 +848,16 @@ void MergeChunk::writeTo(uint8_t *Buf) const {
Builder.write(Buf + OutputSectionOff);
}
+// MinGW specific.
+size_t AbsolutePointerChunk::getSize() const { return Config->Wordsize; }
+
+void AbsolutePointerChunk::writeTo(uint8_t *Buf) const {
+ if (Config->is64()) {
+ write64le(Buf + OutputSectionOff, Value);
+ } else {
+ write32le(Buf + OutputSectionOff, Value);
+ }
+}
+
} // namespace coff
} // namespace lld
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index 9e896531bd9a..f8a0ddd8ef3b 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -36,6 +36,7 @@ class DefinedImportData;
class DefinedRegular;
class ObjFile;
class OutputSection;
+class RuntimePseudoReloc;
class Symbol;
// Mask for permissions (discardable, writable, readable, executable, etc).
@@ -63,6 +64,13 @@ public:
// before calling this function.
virtual void writeTo(uint8_t *Buf) const {}
+ // Called by the writer once before assigning addresses and writing
+ // the output.
+ virtual void readRelocTargets() {}
+
+ // Called if restarting thunk addition.
+ virtual void resetRelocTargets() {}
+
// Called by the writer after an RVA is assigned, but before calling
// getSize().
virtual void finalizeContents() {}
@@ -114,6 +122,10 @@ protected:
public:
// The offset from beginning of the output section. The writer sets a value.
uint64_t OutputSectionOff = 0;
+
+ // Whether this section needs to be kept distinct from other sections during
+ // ICF. This is set by the driver using address-significance tables.
+ bool KeepUnique = false;
};
// A chunk corresponding a section of an input file.
@@ -140,6 +152,8 @@ public:
SectionChunk(ObjFile *File, const coff_section *Header);
static bool classof(const Chunk *C) { return C->kind() == SectionKind; }
+ void readRelocTargets() override;
+ void resetRelocTargets() override;
size_t getSize() const override { return Header->SizeOfRawData; }
ArrayRef<uint8_t> getContents() const;
void writeTo(uint8_t *Buf) const override;
@@ -157,6 +171,8 @@ public:
void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S,
uint64_t P) const;
+ void getRuntimePseudoRelocs(std::vector<RuntimePseudoReloc> &Res);
+
// Called if the garbage collector decides to not include this chunk
// in a final output. It's supposed to print out a log message to stdout.
void printDiscardedMessage() const;
@@ -167,16 +183,6 @@ public:
StringRef getDebugName() override;
- // Returns true if the chunk was not dropped by GC.
- bool isLive() { return Live; }
-
- // Used by the garbage collector.
- void markLive() {
- assert(Config->DoGC && "should only mark things live from GC");
- assert(!isLive() && "Cannot mark an already live section!");
- Live = true;
- }
-
// True if this is a codeview debug info chunk. These will not be laid out in
// the image. Instead they will end up in the PDB, if one is requested.
bool isCodeView() const {
@@ -197,10 +203,13 @@ public:
// Allow iteration over the associated child chunks for this section.
ArrayRef<SectionChunk *> children() const { return AssocChildren; }
+ // The section ID this chunk belongs to in its Obj.
+ uint32_t getSectionNumber() const;
+
// A pointer pointing to a replacement for this chunk.
// Initially it points to "this" object. If this chunk is merged
// with other chunk by ICF, it points to another chunk,
- // and this chunk is considrered as dead.
+ // and this chunk is considered as dead.
SectionChunk *Repl;
// The CRC of the contents as described in the COFF spec 4.5.5.
@@ -217,13 +226,17 @@ public:
ArrayRef<coff_relocation> Relocs;
+ // Used by the garbage collector.
+ bool Live;
+
+ // When inserting a thunk, we need to adjust a relocation to point to
+ // the thunk instead of the actual original target Symbol.
+ std::vector<Symbol *> RelocTargets;
+
private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
- // Used by the garbage collector.
- bool Live;
-
// Used for ICF (Identical COMDAT Folding)
void replace(SectionChunk *Other);
uint32_t Class[2] = {0, 0};
@@ -254,6 +267,7 @@ public:
private:
llvm::StringTableBuilder Builder;
+ bool Finalized = false;
};
// A chunk for common symbols. Common chunks don't have actual data.
@@ -297,7 +311,7 @@ static const uint8_t ImportThunkARM64[] = {
};
// Windows-specific.
-// A chunk for DLL import jump table entry. In a final output, it's
+// A chunk for DLL import jump table entry. In a final output, its
// contents will be a JMP instruction to some __imp_ symbol.
class ImportThunkChunkX64 : public Chunk {
public:
@@ -341,11 +355,22 @@ private:
Defined *ImpSymbol;
};
+class RangeExtensionThunk : public Chunk {
+public:
+ explicit RangeExtensionThunk(Defined *T) : Target(T) {}
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+ Defined *Target;
+};
+
// Windows-specific.
// See comments for DefinedLocalImport class.
class LocalImportChunk : public Chunk {
public:
- explicit LocalImportChunk(Defined *S) : Sym(S) {}
+ explicit LocalImportChunk(Defined *S) : Sym(S) {
+ Alignment = Config->Wordsize;
+ }
size_t getSize() const override;
void getBaserels(std::vector<Baserel> *Res) override;
void writeTo(uint8_t *Buf) const override;
@@ -414,9 +439,73 @@ public:
uint8_t Type;
};
+// This is a placeholder Chunk, to allow attaching a DefinedSynthetic to a
+// specific place in a section, without any data. This is used for the MinGW
+// specific symbol __RUNTIME_PSEUDO_RELOC_LIST_END__, even though the concept
+// of an empty chunk isn't MinGW specific.
+class EmptyChunk : public Chunk {
+public:
+ EmptyChunk() {}
+ size_t getSize() const override { return 0; }
+ void writeTo(uint8_t *Buf) const override {}
+};
+
+// MinGW specific, for the "automatic import of variables from DLLs" feature.
+// This provides the table of runtime pseudo relocations, for variable
+// references that turned out to need to be imported from a DLL even though
+// the reference didn't use the dllimport attribute. The MinGW runtime will
+// process this table after loading, before handling control over to user
+// code.
+class PseudoRelocTableChunk : public Chunk {
+public:
+ PseudoRelocTableChunk(std::vector<RuntimePseudoReloc> &Relocs)
+ : Relocs(std::move(Relocs)) {
+ Alignment = 4;
+ }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ std::vector<RuntimePseudoReloc> Relocs;
+};
+
+// MinGW specific; information about one individual location in the image
+// that needs to be fixed up at runtime after loading. This represents
+// one individual element in the PseudoRelocTableChunk table.
+class RuntimePseudoReloc {
+public:
+ RuntimePseudoReloc(Defined *Sym, SectionChunk *Target, uint32_t TargetOffset,
+ int Flags)
+ : Sym(Sym), Target(Target), TargetOffset(TargetOffset), Flags(Flags) {}
+
+ Defined *Sym;
+ SectionChunk *Target;
+ uint32_t TargetOffset;
+ // The Flags field contains the size of the relocation, in bits. No other
+ // flags are currently defined.
+ int Flags;
+};
+
+// MinGW specific. A Chunk that contains one pointer-sized absolute value.
+class AbsolutePointerChunk : public Chunk {
+public:
+ AbsolutePointerChunk(uint64_t Value) : Value(Value) {
+ Alignment = getSize();
+ }
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) const override;
+
+private:
+ uint64_t Value;
+};
+
void applyMOV32T(uint8_t *Off, uint32_t V);
void applyBranch24T(uint8_t *Off, int32_t V);
+void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift);
+void applyArm64Imm(uint8_t *Off, uint64_t Imm, uint32_t RangeLimit);
+void applyArm64Branch26(uint8_t *Off, int64_t V);
+
} // namespace coff
} // namespace lld
diff --git a/COFF/Config.h b/COFF/Config.h
index 3ae50b868333..8915b6a3bdd8 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -84,6 +84,7 @@ struct Configuration {
bool is64() { return Machine == AMD64 || Machine == ARM64; }
llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
+ size_t Wordsize;
bool Verbose = false;
WindowsSubsystem Subsystem = llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
Symbol *Entry = nullptr;
@@ -94,7 +95,8 @@ struct Configuration {
bool DoICF = true;
bool TailMerge;
bool Relocatable = true;
- bool Force = false;
+ bool ForceMultiple = false;
+ bool ForceUnresolved = false;
bool Debug = false;
bool DebugDwarf = false;
bool DebugGHashes = false;
@@ -195,6 +197,7 @@ struct Configuration {
bool MinGW = false;
bool WarnMissingOrderSymbol = true;
bool WarnLocallyDefinedImported = true;
+ bool WarnDebugInfoUnusable = true;
bool Incremental = true;
bool IntegrityCheck = false;
bool KillAt = false;
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp
index 464abe8e0894..599cc5892a16 100644
--- a/COFF/DLL.cpp
+++ b/COFF/DLL.cpp
@@ -35,8 +35,6 @@ namespace {
// Import table
-static int ptrSize() { return Config->is64() ? 8 : 4; }
-
// A chunk for the import descriptor table.
class HintNameChunk : public Chunk {
public:
@@ -61,8 +59,8 @@ private:
// A chunk for the import descriptor table.
class LookupChunk : public Chunk {
public:
- explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = ptrSize(); }
- size_t getSize() const override { return ptrSize(); }
+ explicit LookupChunk(Chunk *C) : HintName(C) { Alignment = Config->Wordsize; }
+ size_t getSize() const override { return Config->Wordsize; }
void writeTo(uint8_t *Buf) const override {
write32le(Buf + OutputSectionOff, HintName->getRVA());
@@ -76,8 +74,10 @@ public:
// See Microsoft PE/COFF spec 7.1. Import Header for details.
class OrdinalOnlyChunk : public Chunk {
public:
- explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) { Alignment = ptrSize(); }
- size_t getSize() const override { return ptrSize(); }
+ explicit OrdinalOnlyChunk(uint16_t V) : Ordinal(V) {
+ Alignment = Config->Wordsize;
+ }
+ size_t getSize() const override { return Config->Wordsize; }
void writeTo(uint8_t *Buf) const override {
// An import-by-ordinal slot has MSB 1 to indicate that
@@ -230,6 +230,36 @@ static const uint8_t ThunkARM[] = {
0x60, 0x47, // bx ip
};
+static const uint8_t ThunkARM64[] = {
+ 0x11, 0x00, 0x00, 0x90, // adrp x17, #0 __imp_<FUNCNAME>
+ 0x31, 0x02, 0x00, 0x91, // add x17, x17, #0 :lo12:__imp_<FUNCNAME>
+ 0xfd, 0x7b, 0xb3, 0xa9, // stp x29, x30, [sp, #-208]!
+ 0xfd, 0x03, 0x00, 0x91, // mov x29, sp
+ 0xe0, 0x07, 0x01, 0xa9, // stp x0, x1, [sp, #16]
+ 0xe2, 0x0f, 0x02, 0xa9, // stp x2, x3, [sp, #32]
+ 0xe4, 0x17, 0x03, 0xa9, // stp x4, x5, [sp, #48]
+ 0xe6, 0x1f, 0x04, 0xa9, // stp x6, x7, [sp, #64]
+ 0xe0, 0x87, 0x02, 0xad, // stp q0, q1, [sp, #80]
+ 0xe2, 0x8f, 0x03, 0xad, // stp q2, q3, [sp, #112]
+ 0xe4, 0x97, 0x04, 0xad, // stp q4, q5, [sp, #144]
+ 0xe6, 0x9f, 0x05, 0xad, // stp q6, q7, [sp, #176]
+ 0xe1, 0x03, 0x11, 0xaa, // mov x1, x17
+ 0x00, 0x00, 0x00, 0x90, // adrp x0, #0 DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x91, // add x0, x0, #0 :lo12:DELAY_IMPORT_DESCRIPTOR
+ 0x00, 0x00, 0x00, 0x94, // bl #0 __delayLoadHelper2
+ 0xf0, 0x03, 0x00, 0xaa, // mov x16, x0
+ 0xe6, 0x9f, 0x45, 0xad, // ldp q6, q7, [sp, #176]
+ 0xe4, 0x97, 0x44, 0xad, // ldp q4, q5, [sp, #144]
+ 0xe2, 0x8f, 0x43, 0xad, // ldp q2, q3, [sp, #112]
+ 0xe0, 0x87, 0x42, 0xad, // ldp q0, q1, [sp, #80]
+ 0xe6, 0x1f, 0x44, 0xa9, // ldp x6, x7, [sp, #64]
+ 0xe4, 0x17, 0x43, 0xa9, // ldp x4, x5, [sp, #48]
+ 0xe2, 0x0f, 0x42, 0xa9, // ldp x2, x3, [sp, #32]
+ 0xe0, 0x07, 0x41, 0xa9, // ldp x0, x1, [sp, #16]
+ 0xfd, 0x7b, 0xcd, 0xa8, // ldp x29, x30, [sp], #208
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
// A chunk for the delay import thunk.
class ThunkChunkX64 : public Chunk {
public:
@@ -298,11 +328,35 @@ public:
Defined *Helper = nullptr;
};
+class ThunkChunkARM64 : public Chunk {
+public:
+ ThunkChunkARM64(Defined *I, Chunk *D, Defined *H)
+ : Imp(I), Desc(D), Helper(H) {}
+
+ size_t getSize() const override { return sizeof(ThunkARM64); }
+
+ void writeTo(uint8_t *Buf) const override {
+ memcpy(Buf + OutputSectionOff, ThunkARM64, sizeof(ThunkARM64));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Imp->getRVA(), RVA + 0, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Imp->getRVA() & 0xfff, 0);
+ applyArm64Addr(Buf + OutputSectionOff + 52, Desc->getRVA(), RVA + 52, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 56, Desc->getRVA() & 0xfff, 0);
+ applyArm64Branch26(Buf + OutputSectionOff + 60,
+ Helper->getRVA() - RVA - 60);
+ }
+
+ Defined *Imp = nullptr;
+ Chunk *Desc = nullptr;
+ Defined *Helper = nullptr;
+};
+
// A chunk for the import descriptor table.
class DelayAddressChunk : public Chunk {
public:
- explicit DelayAddressChunk(Chunk *C) : Thunk(C) { Alignment = ptrSize(); }
- size_t getSize() const override { return ptrSize(); }
+ explicit DelayAddressChunk(Chunk *C) : Thunk(C) {
+ Alignment = Config->Wordsize;
+ }
+ size_t getSize() const override { return Config->Wordsize; }
void writeTo(uint8_t *Buf) const override {
if (Config->is64()) {
@@ -362,6 +416,8 @@ public:
size_t getSize() const override { return Size * 4; }
void writeTo(uint8_t *Buf) const override {
+ memset(Buf + OutputSectionOff, 0, getSize());
+
for (const Export &E : Config->Exports) {
uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4;
uint32_t Bit = 0;
@@ -418,30 +474,6 @@ private:
} // anonymous namespace
-uint64_t IdataContents::getDirSize() {
- return Dirs.size() * sizeof(ImportDirectoryTableEntry);
-}
-
-uint64_t IdataContents::getIATSize() {
- return Addresses.size() * ptrSize();
-}
-
-// Returns a list of .idata contents.
-// See Microsoft PE/COFF spec 5.4 for details.
-std::vector<Chunk *> IdataContents::getChunks() {
- create();
-
- // The loader assumes a specific order of data.
- // Add each type in the correct order.
- std::vector<Chunk *> V;
- V.insert(V.end(), Dirs.begin(), Dirs.end());
- V.insert(V.end(), Lookups.begin(), Lookups.end());
- V.insert(V.end(), Addresses.begin(), Addresses.end());
- V.insert(V.end(), Hints.begin(), Hints.end());
- V.insert(V.end(), DLLNames.begin(), DLLNames.end());
- return V;
-}
-
void IdataContents::create() {
std::vector<std::vector<DefinedImportData *>> V = binImports(Imports);
@@ -465,8 +497,8 @@ void IdataContents::create() {
Hints.push_back(C);
}
// Terminate with null values.
- Lookups.push_back(make<NullChunk>(ptrSize()));
- Addresses.push_back(make<NullChunk>(ptrSize()));
+ Lookups.push_back(make<NullChunk>(Config->Wordsize));
+ Addresses.push_back(make<NullChunk>(Config->Wordsize));
for (int I = 0, E = Syms.size(); I < E; ++I)
Syms[I]->setLocation(Addresses[Base + I]);
@@ -555,6 +587,8 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *S, Chunk *Dir) {
return make<ThunkChunkX86>(S, Dir, Helper);
case ARMNT:
return make<ThunkChunkARM>(S, Dir, Helper);
+ case ARM64:
+ return make<ThunkChunkARM64>(S, Dir, Helper);
default:
llvm_unreachable("unsupported machine type");
}
diff --git a/COFF/DLL.h b/COFF/DLL.h
index c5d6e7c93abf..a298271e2c0d 100644
--- a/COFF/DLL.h
+++ b/COFF/DLL.h
@@ -19,19 +19,12 @@ namespace coff {
// Windows-specific.
// IdataContents creates all chunks for the DLL import table.
// You are supposed to call add() to add symbols and then
-// call getChunks() to get a list of chunks.
+// call create() to populate the chunk vectors.
class IdataContents {
public:
void add(DefinedImportData *Sym) { Imports.push_back(Sym); }
bool empty() { return Imports.empty(); }
- std::vector<Chunk *> getChunks();
- uint64_t getDirRVA() { return Dirs[0]->getRVA(); }
- uint64_t getDirSize();
- uint64_t getIATRVA() { return Addresses[0]->getRVA(); }
- uint64_t getIATSize();
-
-private:
void create();
std::vector<DefinedImportData *> Imports;
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index eefdb48beadd..2e4b1e6d3147 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -32,6 +32,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TarWriter.h"
@@ -56,7 +57,7 @@ Configuration *Config;
LinkerDriver *Driver;
bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
- errorHandler().LogName = sys::path::filename(Args[0]);
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
errorHandler().ErrorOS = &Diag;
errorHandler().ColorDiagnostics = Diag.has_colors();
errorHandler().ErrorLimitExceededMsg =
@@ -116,6 +117,19 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) {
});
}
+// Symbol names are mangled by prepending "_" on x86.
+static StringRef mangle(StringRef Sym) {
+ assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
+ if (Config->Machine == I386)
+ return Saver.save("_" + Sym);
+ return Sym;
+}
+
+static bool findUnderscoreMangle(StringRef Sym) {
+ StringRef Entry = Symtab->findMangle(mangle(Sym));
+ return !Entry.empty() && !isa<Undefined>(Symtab->find(Entry));
+}
+
MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) {
MemoryBufferRef MBRef = *MB;
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take ownership
@@ -357,13 +371,30 @@ Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
return Path;
}
+// MinGW specific. If an embedded directive specified to link to
+// foo.lib, but it isn't found, try libfoo.a instead.
+StringRef LinkerDriver::doFindLibMinGW(StringRef Filename) {
+ if (Filename.contains('/') || Filename.contains('\\'))
+ return Filename;
+
+ SmallString<128> S = Filename;
+ sys::path::replace_extension(S, ".a");
+ StringRef LibName = Saver.save("lib" + S.str());
+ return doFindFile(LibName);
+}
+
// Find library file from search path.
StringRef LinkerDriver::doFindLib(StringRef Filename) {
// Add ".lib" to Filename if that has no file extension.
bool HasExt = Filename.contains('.');
if (!HasExt)
Filename = Saver.save(Filename + ".lib");
- return doFindFile(Filename);
+ StringRef Ret = doFindFile(Filename);
+ // For MinGW, if the find above didn't turn up anything, try
+ // looking for a MinGW formatted library name.
+ if (Config->MinGW && Ret == Filename)
+ return doFindLibMinGW(Filename);
+ return Ret;
}
// Resolves a library path. /nodefaultlib options are taken into
@@ -407,54 +438,57 @@ Symbol *LinkerDriver::addUndefined(StringRef Name) {
return B;
}
-// Symbol names are mangled by appending "_" prefix on x86.
-StringRef LinkerDriver::mangle(StringRef Sym) {
- assert(Config->Machine != IMAGE_FILE_MACHINE_UNKNOWN);
- if (Config->Machine == I386)
- return Saver.save("_" + Sym);
- return Sym;
-}
-
// Windows specific -- find default entry point name.
//
// 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);
+ assert(Config->Subsystem != IMAGE_SUBSYSTEM_UNKNOWN &&
+ "must handle /subsystem before calling this");
+
+ if (Config->MinGW)
+ return mangle(Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI
+ ? "WinMainCRTStartup"
+ : "mainCRTStartup");
+
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
+ if (findUnderscoreMangle("wWinMain")) {
+ if (!findUnderscoreMangle("WinMain"))
+ return mangle("wWinMainCRTStartup");
+ warn("found both wWinMain and WinMain; using latter");
}
- return "";
+ return mangle("WinMainCRTStartup");
}
-
- // User-defined main functions and their corresponding entry points.
- static const char *Entries[][2] = {
- {"main", "mainCRTStartup"},
- {"wmain", "wmainCRTStartup"},
- {"WinMain", "WinMainCRTStartup"},
- {"wWinMain", "wWinMainCRTStartup"},
- };
- for (auto E : Entries) {
- StringRef Entry = Symtab->findMangle(mangle(E[0]));
- if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry)))
- return mangle(E[1]);
+ if (findUnderscoreMangle("wmain")) {
+ if (!findUnderscoreMangle("main"))
+ return mangle("wmainCRTStartup");
+ warn("found both wmain and main; using latter");
}
- return "";
+ return mangle("mainCRTStartup");
}
WindowsSubsystem LinkerDriver::inferSubsystem() {
if (Config->DLL)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
- if (Symtab->findUnderscore("main") || Symtab->findUnderscore("wmain"))
+ if (Config->MinGW)
return IMAGE_SUBSYSTEM_WINDOWS_CUI;
- if (Symtab->findUnderscore("WinMain") || Symtab->findUnderscore("wWinMain"))
+ // Note that link.exe infers the subsystem from the presence of these
+ // functions even if /entry: or /nodefaultlib are passed which causes them
+ // to not be called.
+ bool HaveMain = findUnderscoreMangle("main");
+ bool HaveWMain = findUnderscoreMangle("wmain");
+ bool HaveWinMain = findUnderscoreMangle("WinMain");
+ bool HaveWWinMain = findUnderscoreMangle("wWinMain");
+ if (HaveMain || HaveWMain) {
+ if (HaveWinMain || HaveWWinMain) {
+ warn(std::string("found ") + (HaveMain ? "main" : "wmain") + " and " +
+ (HaveWinMain ? "WinMain" : "wWinMain") +
+ "; defaulting to /subsystem:console");
+ }
+ return IMAGE_SUBSYSTEM_WINDOWS_CUI;
+ }
+ if (HaveWinMain || HaveWWinMain)
return IMAGE_SUBSYSTEM_WINDOWS_GUI;
return IMAGE_SUBSYSTEM_UNKNOWN;
}
@@ -500,26 +534,65 @@ static std::string createResponseFile(const opt::InputArgList &Args,
return Data.str();
}
-static unsigned getDefaultDebugType(const opt::InputArgList &Args) {
- unsigned DebugTypes = static_cast<unsigned>(DebugType::CV);
+enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab };
+
+static DebugKind parseDebugKind(const opt::InputArgList &Args) {
+ auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt);
+ if (!A)
+ return DebugKind::None;
+ if (A->getNumValues() == 0)
+ return DebugKind::Full;
+
+ DebugKind Debug = StringSwitch<DebugKind>(A->getValue())
+ .CaseLower("none", DebugKind::None)
+ .CaseLower("full", DebugKind::Full)
+ .CaseLower("fastlink", DebugKind::FastLink)
+ // LLD extensions
+ .CaseLower("ghash", DebugKind::GHash)
+ .CaseLower("dwarf", DebugKind::Dwarf)
+ .CaseLower("symtab", DebugKind::Symtab)
+ .Default(DebugKind::Unknown);
+
+ if (Debug == DebugKind::FastLink) {
+ warn("/debug:fastlink unsupported; using /debug:full");
+ return DebugKind::Full;
+ }
+ if (Debug == DebugKind::Unknown) {
+ error("/debug: unknown option: " + Twine(A->getValue()));
+ return DebugKind::None;
+ }
+ return Debug;
+}
+
+static unsigned parseDebugTypes(const opt::InputArgList &Args) {
+ unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
+
+ if (auto *A = Args.getLastArg(OPT_debugtype)) {
+ SmallVector<StringRef, 3> Types;
+ A->getSpelling().split(Types, ',', /*KeepEmpty=*/false);
+
+ for (StringRef Type : Types) {
+ unsigned V = StringSwitch<unsigned>(Type.lower())
+ .Case("cv", static_cast<unsigned>(DebugType::CV))
+ .Case("pdata", static_cast<unsigned>(DebugType::PData))
+ .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
+ .Default(0);
+ if (V == 0) {
+ warn("/debugtype: unknown option: " + Twine(A->getValue()));
+ continue;
+ }
+ DebugTypes |= V;
+ }
+ return DebugTypes;
+ }
+
+ // Default debug types
+ DebugTypes = static_cast<unsigned>(DebugType::CV);
if (Args.hasArg(OPT_driver))
DebugTypes |= static_cast<unsigned>(DebugType::PData);
if (Args.hasArg(OPT_profile))
DebugTypes |= static_cast<unsigned>(DebugType::Fixup);
- return DebugTypes;
-}
-static unsigned parseDebugType(StringRef Arg) {
- SmallVector<StringRef, 3> Types;
- Arg.split(Types, ',', /*KeepEmpty=*/false);
-
- unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
- for (StringRef Type : Types)
- DebugTypes |= StringSwitch<unsigned>(Type.lower())
- .Case("cv", static_cast<unsigned>(DebugType::CV))
- .Case("pdata", static_cast<unsigned>(DebugType::PData))
- .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
- .Default(0);
return DebugTypes;
}
@@ -679,131 +752,6 @@ static void parseModuleDefs(StringRef Path) {
}
}
-// A helper function for filterBitcodeFiles.
-static bool needsRebuilding(MemoryBufferRef MB) {
- // The MSVC linker doesn't support thin archives, so if it's a thin
- // archive, we always need to rebuild it.
- std::unique_ptr<Archive> File =
- CHECK(Archive::create(MB), "Failed to read " + MB.getBufferIdentifier());
- if (File->isThin())
- return true;
-
- // Returns true if the archive contains at least one bitcode file.
- for (MemoryBufferRef Member : getArchiveMembers(File.get()))
- if (identify_magic(Member.getBuffer()) == file_magic::bitcode)
- return true;
- return false;
-}
-
-// Opens a given path as an archive file and removes bitcode files
-// from them if exists. This function is to appease the MSVC linker as
-// their linker doesn't like archive files containing non-native
-// object files.
-//
-// If a given archive doesn't contain bitcode files, the archive path
-// is returned as-is. Otherwise, a new temporary file is created and
-// its path is returned.
-static Optional<std::string>
-filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) {
- std::unique_ptr<MemoryBuffer> MB = CHECK(
- MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path);
- MemoryBufferRef MBRef = MB->getMemBufferRef();
- file_magic Magic = identify_magic(MBRef.getBuffer());
-
- if (Magic == file_magic::bitcode)
- return None;
- if (Magic != file_magic::archive)
- return Path.str();
- if (!needsRebuilding(MBRef))
- return Path.str();
-
- std::unique_ptr<Archive> File =
- CHECK(Archive::create(MBRef),
- MBRef.getBufferIdentifier() + ": failed to parse archive");
-
- std::vector<NewArchiveMember> New;
- for (MemoryBufferRef Member : getArchiveMembers(File.get()))
- if (identify_magic(Member.getBuffer()) != file_magic::bitcode)
- New.emplace_back(Member);
-
- if (New.empty())
- return None;
-
- log("Creating a temporary archive for " + Path + " to remove bitcode files");
-
- SmallString<128> S;
- if (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);
-
- Error E =
- llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU,
- /*Deterministics=*/true,
- /*Thin=*/false);
- handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
- error("failed to create a new archive " + S.str() + ": " + EI.message());
- });
- return Temp;
-}
-
-// Create response file contents and invoke the MSVC linker.
-void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
- std::string Rsp = "/nologo\n";
- std::vector<std::string> Temps;
-
- // Write out archive members that we used in symbol resolution and pass these
- // to MSVC before any archives, so that MSVC uses the same objects to satisfy
- // references.
- for (ObjFile *Obj : ObjFile::Instances) {
- if (Obj->ParentName.empty())
- continue;
- SmallString<128> S;
- int Fd;
- if (auto EC = sys::fs::createTemporaryFile(
- "lld-" + sys::path::filename(Obj->ParentName), ".obj", Fd, S))
- fatal("cannot create a temporary file: " + EC.message());
- raw_fd_ostream OS(Fd, /*shouldClose*/ true);
- OS << Obj->MB.getBuffer();
- Temps.push_back(S.str());
- Rsp += quote(S) + "\n";
- }
-
- for (auto *Arg : Args) {
- switch (Arg->getOption().getID()) {
- case OPT_linkrepro:
- case OPT_lldmap:
- case OPT_lldmap_file:
- case OPT_lldsavetemps:
- case OPT_msvclto:
- // LLD-specific options are stripped.
- break;
- case OPT_opt:
- if (!StringRef(Arg->getValue()).startswith("lld"))
- Rsp += toString(*Arg) + " ";
- break;
- case OPT_INPUT: {
- if (Optional<StringRef> Path = doFindFile(Arg->getValue())) {
- if (Optional<std::string> S = filterBitcodeFiles(*Path, Temps))
- Rsp += quote(*S) + "\n";
- continue;
- }
- Rsp += quote(Arg->getValue()) + "\n";
- break;
- }
- default:
- Rsp += toString(*Arg) + "\n";
- }
- }
-
- std::vector<StringRef> ObjFiles = Symtab->compileBitcodeFiles();
- runMSVCLinker(Rsp, ObjFiles);
-
- for (StringRef Path : Temps)
- sys::fs::remove(Path);
-}
-
void LinkerDriver::enqueueTask(std::function<void()> Task) {
TaskQueue.push_back(std::move(Task));
}
@@ -859,6 +807,97 @@ static void parseOrderFile(StringRef Arg) {
}
}
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (Chunk *C = D->getChunk())
+ C->KeepUnique = true;
+}
+
+static void findKeepUniqueSections() {
+ // Exported symbols could be address-significant in other executables or DSOs,
+ // so we conservatively mark them as address-significant.
+ for (Export &R : Config->Exports)
+ markAddrsig(R.Sym);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (ObjFile *Obj : ObjFile::Instances) {
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents;
+ Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents);
+ 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(Obj) + ": could not decode addrsig section: " + Err);
+ if (SymIndex >= Syms.size())
+ fatal(toString(Obj) + ": invalid symbol index in addrsig section");
+ 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);
+ }
+ }
+}
+
+// link.exe replaces each %foo% in AltPath with the contents of environment
+// variable foo, and adds the two magic env vars _PDB (expands to the basename
+// of pdb's output path) and _EXT (expands to the extension of the output
+// binary).
+// lld only supports %_PDB% and %_EXT% and warns on references to all other env
+// vars.
+static void parsePDBAltPath(StringRef AltPath) {
+ SmallString<128> Buf;
+ StringRef PDBBasename =
+ sys::path::filename(Config->PDBPath, sys::path::Style::windows);
+ StringRef BinaryExtension =
+ sys::path::extension(Config->OutputFile, sys::path::Style::windows);
+ if (!BinaryExtension.empty())
+ BinaryExtension = BinaryExtension.substr(1); // %_EXT% does not include '.'.
+
+ // Invariant:
+ // +--------- Cursor ('a...' might be the empty string).
+ // | +----- FirstMark
+ // | | +- SecondMark
+ // v v v
+ // a...%...%...
+ size_t Cursor = 0;
+ while (Cursor < AltPath.size()) {
+ size_t FirstMark, SecondMark;
+ if ((FirstMark = AltPath.find('%', Cursor)) == StringRef::npos ||
+ (SecondMark = AltPath.find('%', FirstMark + 1)) == StringRef::npos) {
+ // Didn't find another full fragment, treat rest of string as literal.
+ Buf.append(AltPath.substr(Cursor));
+ break;
+ }
+
+ // Found a full fragment. Append text in front of first %, and interpret
+ // text between first and second % as variable name.
+ Buf.append(AltPath.substr(Cursor, FirstMark - Cursor));
+ StringRef Var = AltPath.substr(FirstMark, SecondMark - FirstMark + 1);
+ if (Var.equals_lower("%_pdb%"))
+ Buf.append(PDBBasename);
+ else if (Var.equals_lower("%_ext%"))
+ Buf.append(BinaryExtension);
+ else {
+ warn("only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping " +
+ Var + " as literal");
+ Buf.append(Var);
+ }
+
+ Cursor = SecondMark + 1;
+ }
+
+ Config->PDBAltPath = Buf;
+}
+
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.
@@ -947,11 +986,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /ignore
for (auto *Arg : Args.filtered(OPT_ignore)) {
- if (StringRef(Arg->getValue()) == "4037")
- Config->WarnMissingOrderSymbol = false;
- else if (StringRef(Arg->getValue()) == "4217")
- Config->WarnLocallyDefinedImported = false;
- // Other warning numbers are ignored.
+ SmallVector<StringRef, 8> Vec;
+ StringRef(Arg->getValue()).split(Vec, ',');
+ for (StringRef S : Vec) {
+ if (S == "4037")
+ Config->WarnMissingOrderSymbol = false;
+ else if (S == "4099")
+ Config->WarnDebugInfoUnusable = false;
+ else if (S == "4217")
+ Config->WarnLocallyDefinedImported = false;
+ // Other warning numbers are ignored.
+ }
}
// Handle /out
@@ -965,20 +1010,26 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /force or /force:unresolved
if (Args.hasArg(OPT_force, OPT_force_unresolved))
- Config->Force = true;
+ Config->ForceUnresolved = true;
+
+ // Handle /force or /force:multiple
+ if (Args.hasArg(OPT_force, OPT_force_multiple))
+ Config->ForceMultiple = true;
// Handle /debug
- if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) {
+ DebugKind Debug = parseDebugKind(Args);
+ if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf ||
+ Debug == DebugKind::GHash) {
Config->Debug = true;
Config->Incremental = true;
- if (auto *Arg = Args.getLastArg(OPT_debugtype))
- Config->DebugTypes = parseDebugType(Arg->getValue());
- else
- Config->DebugTypes = getDefaultDebugType(Args);
}
+ // Handle /debugtype
+ Config->DebugTypes = parseDebugTypes(Args);
+
// Handle /pdb
- bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash);
+ bool ShouldCreatePDB =
+ (Debug == DebugKind::Full || Debug == DebugKind::GHash);
if (ShouldCreatePDB) {
if (auto *Arg = Args.getLastArg(OPT_pdb))
Config->PDBPath = Arg->getValue();
@@ -1099,7 +1150,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->Implib = Arg->getValue();
// Handle /opt.
- bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile);
+ bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile);
unsigned ICFLevel =
Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on
unsigned TailMerge = 1;
@@ -1184,6 +1235,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
parseMerge(".xdata=.rdata");
parseMerge(".bss=.data");
+ if (Config->MinGW) {
+ parseMerge(".ctors=.rdata");
+ parseMerge(".dtors=.rdata");
+ parseMerge(".CRT=.rdata");
+ }
+
// Handle /section
for (auto *Arg : Args.filtered(OPT_section))
parseSection(Arg->getValue());
@@ -1237,9 +1294,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_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->DebugDwarf = Debug == DebugKind::Dwarf;
+ Config->DebugGHashes = Debug == DebugKind::GHash;
+ Config->DebugSymtab = Debug == DebugKind::Symtab;
Config->MapFile = getMapFile(Args);
@@ -1269,10 +1326,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
std::set<sys::fs::UniqueID> WholeArchives;
- for (auto *Arg : Args.filtered(OPT_wholearchive_file))
- if (Optional<StringRef> Path = doFindFile(Arg->getValue()))
+ AutoExporter Exporter;
+ 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);
+ Exporter.addWholeArchive(*Path);
+ }
+ }
// A predicate returning true if a given path is an argument for
// /wholearchive:, or /wholearchive is enabled globally.
@@ -1303,12 +1364,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Read all input files given via the command line.
run();
+ if (errorCount())
+ return;
+
// We should have inferred a machine type by now from the input files, but if
// not we assume x64.
if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
warn("/machine is not specified. x64 is assumed");
Config->Machine = AMD64;
}
+ Config->Wordsize = Config->is64() ? 8 : 4;
// Input files can be Windows resource files (.res files). We use
// WindowsResource to convert resource files to a regular COFF file,
@@ -1335,25 +1400,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
error("/dynamicbase:no is not compatible with " +
machineToStr(Config->Machine));
- // Handle /entry and /dll
- if (auto *Arg = Args.getLastArg(OPT_entry)) {
- Config->Entry = addUndefined(mangle(Arg->getValue()));
- } else if (!Config->Entry && !Config->NoEntry) {
- if (Args.hasArg(OPT_dll)) {
- StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
- : "_DllMainCRTStartup";
- Config->Entry = addUndefined(S);
- } else {
- // Windows specific -- If entry point name is not given, we need to
- // infer that from user-defined entry name.
- StringRef S = findDefaultEntry();
- if (S.empty())
- fatal("entry point must be defined");
- Config->Entry = addUndefined(S);
- log("Entry name inferred: " + S);
- }
- }
-
// Handle /export
for (auto *Arg : Args.filtered(OPT_export)) {
Export E = parseExport(Arg->getValue());
@@ -1379,6 +1425,34 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
return;
}
+ // Windows specific -- if no /subsystem is given, we need to infer
+ // that from entry point name. Must happen before /entry handling,
+ // and after the early return when just writing an import library.
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
+ Config->Subsystem = inferSubsystem();
+ if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
+ fatal("subsystem must be defined");
+ }
+
+ // Handle /entry and /dll
+ if (auto *Arg = Args.getLastArg(OPT_entry)) {
+ Config->Entry = addUndefined(mangle(Arg->getValue()));
+ } else if (!Config->Entry && !Config->NoEntry) {
+ if (Args.hasArg(OPT_dll)) {
+ StringRef S = (Config->Machine == I386) ? "__DllMainCRTStartup@12"
+ : "_DllMainCRTStartup";
+ Config->Entry = addUndefined(S);
+ } else {
+ // Windows specific -- If entry point name is not given, we need to
+ // infer that from user-defined entry name.
+ StringRef S = findDefaultEntry();
+ if (S.empty())
+ fatal("entry point must be defined");
+ Config->Entry = addUndefined(S);
+ log("Entry name inferred: " + S);
+ }
+ }
+
// Handle /delayload
for (auto *Arg : Args.filtered(OPT_delayload)) {
Config->DelayLoads.insert(StringRef(Arg->getValue()).lower());
@@ -1412,6 +1486,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// tools won't work correctly if these assumptions are not held.
sys::fs::make_absolute(Config->PDBAltPath);
sys::path::remove_dots(Config->PDBAltPath);
+ } else {
+ // Don't do this earlier, so that Config->OutputFile is ready.
+ parsePDBAltPath(Config->PDBAltPath);
}
}
@@ -1435,6 +1512,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Needed for MSVC 2017 15.5 CRT.
Symtab->addAbsolute(mangle("__enclave_config"), 0);
+ if (Config->MinGW) {
+ Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST__"), 0);
+ Symtab->addAbsolute(mangle("__RUNTIME_PSEUDO_RELOC_LIST_END__"), 0);
+ Symtab->addAbsolute(mangle("__CTOR_LIST__"), 0);
+ Symtab->addAbsolute(mangle("__DTOR_LIST__"), 0);
+ }
+
// This code may add new undefined symbols to the link, which may enqueue more
// symbol resolution tasks, so we need to continue executing tasks until we
// converge.
@@ -1474,31 +1558,34 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (errorCount())
return;
- // If /msvclto is given, we use the MSVC linker to link LTO output files.
- // This is useful because MSVC link.exe can generate complete PDBs.
- if (Args.hasArg(OPT_msvclto)) {
- invokeMSVC(Args);
- return;
- }
-
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
Symtab->addCombinedLTOObjects();
run();
+ if (Config->MinGW) {
+ // Load any further object files that might be needed for doing automatic
+ // imports.
+ //
+ // For cases with no automatically imported symbols, this iterates once
+ // over the symbol table and doesn't do anything.
+ //
+ // For the normal case with a few automatically imported symbols, this
+ // should only need to be run once, since each new object file imported
+ // is an import library and wouldn't add any new undefined references,
+ // but there's nothing stopping the __imp_ symbols from coming from a
+ // normal object file as well (although that won't be used for the
+ // actual autoimport later on). If this pass adds new undefined references,
+ // we won't iterate further to resolve them.
+ Symtab->loadMinGWAutomaticImports();
+ run();
+ }
+
// Make sure we have resolved all symbols.
Symtab->reportRemainingUndefines();
if (errorCount())
return;
- // Windows specific -- if no /subsystem is given, we need to infer
- // that from entry point name.
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
- Config->Subsystem = inferSubsystem();
- if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN)
- fatal("subsystem must be defined");
- }
-
// Handle /safeseh.
if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) {
for (ObjFile *File : ObjFile::Instances)
@@ -1512,7 +1599,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// are chosen to be exported.
if (Config->DLL && ((Config->MinGW && Config->Exports.empty()) ||
Args.hasArg(OPT_export_all_symbols))) {
- AutoExporter Exporter;
+ Exporter.initSymbolExcludes();
Symtab->forEachSymbol([=](Symbol *S) {
auto *Def = dyn_cast<Defined>(S);
@@ -1551,11 +1638,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
continue;
}
+ // If the symbol isn't common, it must have been replaced with a regular
+ // symbol, which will carry its own alignment.
auto *DC = dyn_cast<DefinedCommon>(Sym);
- if (!DC) {
- warn("/aligncomm symbol " + Name + " of wrong kind");
+ if (!DC)
continue;
- }
CommonChunk *C = DC->getChunk();
C->Alignment = std::max(C->Alignment, Alignment);
@@ -1576,8 +1663,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
markLive(Symtab->getChunks());
// Identify identical COMDAT sections to merge them.
- if (Config->DoICF)
+ if (Config->DoICF) {
+ findKeepUniqueSections();
doICF(Symtab->getChunks());
+ }
// Write the result.
writeResult();
diff --git a/COFF/Driver.h b/COFF/Driver.h
index 627e991a9028..e779721ab75d 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -89,6 +89,7 @@ private:
Optional<StringRef> findLib(StringRef Filename);
StringRef doFindFile(StringRef Filename);
StringRef doFindLib(StringRef Filename);
+ StringRef doFindLibMinGW(StringRef Filename);
// Parses LIB environment which contains a list of search paths.
void addLibSearchPaths();
@@ -103,7 +104,6 @@ private:
std::set<std::string> VisitedLibs;
Symbol *addUndefined(StringRef Sym);
- StringRef mangle(StringRef Sym);
// Windows specific -- "main" is not the only main function in Windows.
// You can choose one from these four -- {w,}{WinMain,main}.
@@ -115,8 +115,6 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
- void invokeMSVC(llvm::opt::InputArgList &Args);
-
void addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive);
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
StringRef ParentName);
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index c12e791f9507..3a11895497a4 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -713,26 +713,6 @@ MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
return MBRef;
}
-// Run MSVC link.exe for given in-memory object files.
-// Command line options are copied from those given to LLD.
-// This is for the /msvclto option.
-void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects) {
- // Write the in-memory object files to disk.
- std::vector<TemporaryFile> Temps;
- for (StringRef S : Objects) {
- Temps.emplace_back("lto", "obj", S);
- Rsp += quote(Temps.back().Path) + "\n";
- }
-
- log("link.exe " + Rsp);
-
- // Run MSVC link.exe.
- Temps.emplace_back("lto", "rsp", Rsp);
- Executor E("link.exe");
- E.add(Twine("@" + Temps.back().Path));
- E.run();
-}
-
// Create OptTable
// Create prefix string literals used in Options.td
@@ -883,7 +863,9 @@ std::vector<const char *> ArgParser::tokenize(StringRef S) {
}
void printHelp(const char *Argv0) {
- COFFOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false);
+ COFFOptTable().PrintHelp(outs(),
+ (std::string(Argv0) + " [options] file...").c_str(),
+ "LLVM Linker", false);
}
} // namespace coff
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 7feb3c4e0b0c..34ea360fa925 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -22,6 +22,7 @@
#include "Chunks.h"
#include "Symbols.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
#include "lld/Common/Timer.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Debug.h"
@@ -80,7 +81,7 @@ private:
bool ICF::isEligible(SectionChunk *C) {
// Non-comdat chunks, dead chunks, and writable chunks are not elegible.
bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE;
- if (!C->isCOMDAT() || !C->isLive() || Writable)
+ if (!C->isCOMDAT() || !C->Live || Writable)
return false;
// Code sections are eligible.
@@ -93,7 +94,11 @@ bool ICF::isEligible(SectionChunk *C) {
return true;
// So are vtables.
- return C->Sym && C->Sym->getName().startswith("??_7");
+ if (C->Sym && C->Sym->getName().startswith("??_7"))
+ return true;
+
+ // Anything else not in an address-significance table is eligible.
+ return !C->KeepUnique;
}
// Split an equivalence class into smaller classes.
@@ -222,10 +227,10 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> 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) {
+ parallelForEachN(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) {
+ parallelForEachN(1, NumShards + 1, [&](size_t I) {
if (Boundaries[I - 1] < Boundaries[I]) {
forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn);
}
@@ -257,9 +262,19 @@ void ICF::run(ArrayRef<Chunk *> Vec) {
SC->Class[0] = NextId++;
// Initially, we use hash values to partition sections.
- for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) {
+ parallelForEach(Chunks, [&](SectionChunk *SC) {
+ SC->Class[1] = xxHash64(SC->getContents());
+ });
+
+ // Combine the hashes of the sections referenced by each section into its
+ // hash.
+ parallelForEach(Chunks, [&](SectionChunk *SC) {
+ uint32_t Hash = SC->Class[1];
+ for (Symbol *B : SC->symbols())
+ if (auto *Sym = dyn_cast_or_null<DefinedRegular>(B))
+ Hash ^= Sym->getChunk()->Class[1];
// Set MSB to 1 to avoid collisions with non-hash classs.
- SC->Class[0] = xxHash64(SC->getContents()) | (1 << 31);
+ SC->Class[0] = Hash | (1U << 31);
});
// From now on, sections in Chunks are ordered so that sections in
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index 2b3e65fae04b..236c90ef0388 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -54,8 +54,16 @@ std::vector<BitcodeFile *> BitcodeFile::Instances;
static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
Symbol *Source, Symbol *Target) {
if (auto *U = dyn_cast<Undefined>(Source)) {
- if (U->WeakAlias && U->WeakAlias != Target)
+ if (U->WeakAlias && U->WeakAlias != Target) {
+ // Weak aliases as produced by GCC are named in the form
+ // .weak.<weaksymbol>.<othersymbol>, where <othersymbol> is the name
+ // of another symbol emitted near the weak symbol.
+ // Just use the definition from the first object file that defined
+ // this weak symbol.
+ if (Config->MinGW)
+ return;
Symtab->reportDuplicate(Source, F);
+ }
U->WeakAlias = Target;
}
}
@@ -147,9 +155,10 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
const coff_aux_section_definition *Def,
StringRef LeaderName) {
const coff_section *Sec;
- StringRef Name;
if (auto EC = COFFObj->getSection(SectionNumber, Sec))
fatal("getSection failed: #" + Twine(SectionNumber) + ": " + EC.message());
+
+ StringRef Name;
if (auto EC = COFFObj->getSectionName(Sec, Name))
fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " +
EC.message());
@@ -161,6 +170,11 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
return nullptr;
}
+ if (Name == ".llvm_addrsig") {
+ AddrsigSec = Sec;
+ return nullptr;
+ }
+
// Object files may have DWARF debug info or MS CodeView debug info
// (or both).
//
@@ -168,8 +182,8 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
// of the linker; they are just a data section containing relocations.
// We can just link them to complete debug info.
//
- // CodeView needs a linker support. We need to interpret and debug
- // info, and then write it to a separate .pdb file.
+ // CodeView needs linker support. We need to interpret debug info,
+ // and then write it to a separate .pdb file.
// Ignore DWARF debug info unless /debug is given.
if (!Config->Debug && Name.startswith(".debug_"))
@@ -205,7 +219,13 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
void ObjFile::readAssociativeDefinition(
COFFSymbolRef Sym, const coff_aux_section_definition *Def) {
- SectionChunk *Parent = SparseChunks[Def->getNumber(Sym.isBigObj())];
+ readAssociativeDefinition(Sym, Def, Def->getNumber(Sym.isBigObj()));
+}
+
+void ObjFile::readAssociativeDefinition(COFFSymbolRef Sym,
+ const coff_aux_section_definition *Def,
+ uint32_t ParentSection) {
+ SectionChunk *Parent = SparseChunks[ParentSection];
// If the parent is pending, it probably means that its section definition
// appears after us in the symbol table. Leave the associated section as
@@ -225,6 +245,35 @@ void ObjFile::readAssociativeDefinition(
}
}
+void ObjFile::recordPrevailingSymbolForMingw(
+ COFFSymbolRef Sym, DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
+ // For comdat symbols in executable sections, where this is the copy
+ // of the section chunk we actually include instead of discarding it,
+ // add the symbol to a map to allow using it for implicitly
+ // associating .[px]data$<func> sections to it.
+ int32_t SectionNumber = Sym.getSectionNumber();
+ SectionChunk *SC = SparseChunks[SectionNumber];
+ if (SC && SC->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ PrevailingSectionMap[Name] = SectionNumber;
+ }
+}
+
+void ObjFile::maybeAssociateSEHForMingw(
+ COFFSymbolRef Sym, const coff_aux_section_definition *Def,
+ const DenseMap<StringRef, uint32_t> &PrevailingSectionMap) {
+ StringRef Name;
+ COFFObj->getSymbolName(Sym, Name);
+ if (Name.consume_front(".pdata$") || Name.consume_front(".xdata$")) {
+ // For MinGW, treat .[px]data$<func> as implicitly associative to
+ // the symbol <func>.
+ auto ParentSym = PrevailingSectionMap.find(Name);
+ if (ParentSym != PrevailingSectionMap.end())
+ readAssociativeDefinition(Sym, Def, ParentSym->second);
+ }
+}
+
Symbol *ObjFile::createRegular(COFFSymbolRef Sym) {
SectionChunk *SC = SparseChunks[Sym.getSectionNumber()];
if (Sym.isExternal()) {
@@ -232,10 +281,17 @@ Symbol *ObjFile::createRegular(COFFSymbolRef Sym) {
COFFObj->getSymbolName(Sym, Name);
if (SC)
return Symtab->addRegular(this, Name, Sym.getGeneric(), SC);
+ // For MinGW symbols named .weak.* that point to a discarded section,
+ // don't create an Undefined symbol. If nothing ever refers to the symbol,
+ // everything should be fine. If something actually refers to the symbol
+ // (e.g. the undefined weak alias), linking will fail due to undefined
+ // references at the end.
+ if (Config->MinGW && Name.startswith(".weak."))
+ return nullptr;
return Symtab->addUndefined(Name, this, false);
}
if (SC)
- return make<DefinedRegular>(this, /*Name*/ "", false,
+ return make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
/*IsExternal*/ false, Sym.getGeneric(), SC);
return nullptr;
}
@@ -248,19 +304,24 @@ void ObjFile::initializeSymbols() {
std::vector<uint32_t> PendingIndexes;
PendingIndexes.reserve(NumSymbols);
+ DenseMap<StringRef, uint32_t> PrevailingSectionMap;
std::vector<const coff_aux_section_definition *> ComdatDefs(
COFFObj->getNumberOfSections() + 1);
for (uint32_t I = 0; I < NumSymbols; ++I) {
COFFSymbolRef COFFSym = check(COFFObj->getSymbol(I));
+ bool PrevailingComdat;
if (COFFSym.isUndefined()) {
Symbols[I] = createUndefined(COFFSym);
} else if (COFFSym.isWeakExternal()) {
Symbols[I] = createUndefined(COFFSym);
uint32_t TagIndex = COFFSym.getAux<coff_aux_weak_external>()->TagIndex;
WeakAliases.emplace_back(Symbols[I], TagIndex);
- } else if (Optional<Symbol *> OptSym = createDefined(COFFSym, ComdatDefs)) {
+ } else if (Optional<Symbol *> OptSym =
+ createDefined(COFFSym, ComdatDefs, PrevailingComdat)) {
Symbols[I] = *OptSym;
+ if (Config->MinGW && PrevailingComdat)
+ recordPrevailingSymbolForMingw(COFFSym, PrevailingSectionMap);
} else {
// createDefined() returns None if a symbol belongs to a section that
// was pending at the point when the symbol was read. This can happen in
@@ -278,9 +339,12 @@ void ObjFile::initializeSymbols() {
for (uint32_t I : PendingIndexes) {
COFFSymbolRef Sym = check(COFFObj->getSymbol(I));
- if (auto *Def = Sym.getSectionDefinition())
+ if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
readAssociativeDefinition(Sym, Def);
+ else if (Config->MinGW)
+ maybeAssociateSEHForMingw(Sym, Def, PrevailingSectionMap);
+ }
if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) {
StringRef Name;
COFFObj->getSymbolName(Sym, Name);
@@ -306,7 +370,9 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) {
Optional<Symbol *> ObjFile::createDefined(
COFFSymbolRef Sym,
- std::vector<const coff_aux_section_definition *> &ComdatDefs) {
+ std::vector<const coff_aux_section_definition *> &ComdatDefs,
+ bool &Prevailing) {
+ Prevailing = false;
auto GetName = [&]() {
StringRef S;
COFFObj->getSymbolName(Sym, S);
@@ -352,12 +418,11 @@ Optional<Symbol *> ObjFile::createDefined(
if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) {
ComdatDefs[SectionNumber] = nullptr;
Symbol *Leader;
- bool Prevailing;
if (Sym.isExternal()) {
std::tie(Leader, Prevailing) =
Symtab->addComdat(this, GetName(), Sym.getGeneric());
} else {
- Leader = make<DefinedRegular>(this, /*Name*/ "", false,
+ Leader = make<DefinedRegular>(this, /*Name*/ "", /*IsCOMDAT*/ false,
/*IsExternal*/ false, Sym.getGeneric());
Prevailing = true;
}
@@ -377,7 +442,7 @@ Optional<Symbol *> ObjFile::createDefined(
// leader symbol by setting the section's ComdatDefs pointer if we encounter a
// non-associative comdat.
if (SparseChunks[SectionNumber] == PendingComdat) {
- if (auto *Def = Sym.getSectionDefinition()) {
+ if (const coff_aux_section_definition *Def = Sym.getSectionDefinition()) {
if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE)
readAssociativeDefinition(Sym, Def);
else
@@ -385,8 +450,10 @@ Optional<Symbol *> ObjFile::createDefined(
}
}
+ // readAssociativeDefinition() writes to SparseChunks, so need to check again.
if (SparseChunks[SectionNumber] == PendingComdat)
return None;
+
return createRegular(Sym);
}
@@ -437,6 +504,10 @@ void ImportFile::parse() {
ExternalName = ExtName;
ImpSym = Symtab->addImportData(ImpName, this);
+ // If this was a duplicate, we logged an error but may continue;
+ // in this case, ImpSym is nullptr.
+ if (!ImpSym)
+ return;
if (Hdr->getType() == llvm::COFF::IMPORT_CONST)
static_cast<void>(Symtab->addImportData(Name, this));
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index 4ee4b363886f..ec802f2d0300 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -13,7 +13,9 @@
#include "Config.h"
#include "lld/Common/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
@@ -121,9 +123,12 @@ public:
return Symbols[SymbolIndex];
}
- // Returns the underying COFF file.
+ // Returns the underlying COFF file.
COFFObjectFile *getCOFFObj() { return COFFObj.get(); }
+ // Whether the object was already merged into the final PDB or not
+ bool wasProcessedForPDB() const { return !!ModuleDBI; }
+
static std::vector<ObjFile *> Instances;
// Flags in the absolute @feat.00 symbol if it is present. These usually
@@ -144,6 +149,13 @@ public:
// if we are not producing a PDB.
llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+ const coff_section *AddrsigSec = nullptr;
+
+ // When using Microsoft precompiled headers, this is the PCH's key.
+ // The same key is used by both the precompiled object, and objects using the
+ // precompiled object. Any difference indicates out-of-date objects.
+ llvm::Optional<uint32_t> PCHSignature;
+
private:
void initializeChunks();
void initializeSymbols();
@@ -157,10 +169,24 @@ private:
COFFSymbolRef COFFSym,
const llvm::object::coff_aux_section_definition *Def);
+ void readAssociativeDefinition(
+ COFFSymbolRef COFFSym,
+ const llvm::object::coff_aux_section_definition *Def,
+ uint32_t ParentSection);
+
+ void recordPrevailingSymbolForMingw(
+ COFFSymbolRef COFFSym,
+ llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+
+ void maybeAssociateSEHForMingw(
+ COFFSymbolRef Sym, const llvm::object::coff_aux_section_definition *Def,
+ const llvm::DenseMap<StringRef, uint32_t> &PrevailingSectionMap);
+
llvm::Optional<Symbol *>
createDefined(COFFSymbolRef Sym,
std::vector<const llvm::object::coff_aux_section_definition *>
- &ComdatDefs);
+ &ComdatDefs,
+ bool &PrevailingComdat);
Symbol *createRegular(COFFSymbolRef Sym);
Symbol *createUndefined(COFFSymbolRef Sym);
diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp
index 93f7ba3f9e4c..92d9ff0937c0 100644
--- a/COFF/LTO.cpp
+++ b/COFF/LTO.cpp
@@ -60,6 +60,9 @@ static std::unique_ptr<lto::LTO> createLTO() {
C.DisableVerify = true;
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
+ C.CPU = GetCPUStr();
+ C.MAttrs = GetMAttrs();
+
if (Config->SaveTemps)
checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".",
/*UseInputModulePath*/ true));
diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp
index 6ca1b6647bd7..fd4894250223 100644
--- a/COFF/MapFile.cpp
+++ b/COFF/MapFile.cpp
@@ -110,7 +110,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize);
OS << Sec->Name << '\n';
- for (Chunk *C : Sec->getChunks()) {
+ for (Chunk *C : Sec->Chunks) {
auto *SC = dyn_cast<SectionChunk>(C);
if (!SC)
continue;
diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp
index 57ae450a9138..18b1c9c2529f 100644
--- a/COFF/MarkLive.cpp
+++ b/COFF/MarkLive.cpp
@@ -32,13 +32,13 @@ void markLive(ArrayRef<Chunk *> Chunks) {
// COMDAT section chunks are dead by default. Add non-COMDAT chunks.
for (Chunk *C : Chunks)
if (auto *SC = dyn_cast<SectionChunk>(C))
- if (SC->isLive())
+ if (SC->Live)
Worklist.push_back(SC);
auto Enqueue = [&](SectionChunk *C) {
- if (C->isLive())
+ if (C->Live)
return;
- C->markLive();
+ C->Live = true;
Worklist.push_back(C);
};
@@ -57,7 +57,7 @@ void markLive(ArrayRef<Chunk *> Chunks) {
while (!Worklist.empty()) {
SectionChunk *SC = Worklist.pop_back_val();
- assert(SC->isLive() && "We mark as live when pushing onto the worklist!");
+ assert(SC->Live && "We mark as live when pushing onto the worklist!");
// Mark all symbols listed in the relocation table for this section.
for (Symbol *B : SC->symbols())
diff --git a/COFF/MinGW.cpp b/COFF/MinGW.cpp
index 2ca00587331f..b2c8c4eadca4 100644
--- a/COFF/MinGW.cpp
+++ b/COFF/MinGW.cpp
@@ -19,7 +19,23 @@ using namespace lld::coff;
using namespace llvm;
using namespace llvm::COFF;
-AutoExporter::AutoExporter() {
+void AutoExporter::initSymbolExcludes() {
+ ExcludeSymbolPrefixes = {
+ // Import symbols
+ "__imp_",
+ "__IMPORT_DESCRIPTOR_",
+ // Extra import symbols from GNU import libraries
+ "__nm_",
+ // C++ symbols
+ "__rtti_",
+ "__builtin_",
+ // Artifical symbols such as .refptr
+ ".",
+ };
+ ExcludeSymbolSuffixes = {
+ "_iname",
+ "_NULL_THUNK_DATA",
+ };
if (Config->Machine == I386) {
ExcludeSymbols = {
"__NULL_IMPORT_DESCRIPTOR",
@@ -36,9 +52,10 @@ AutoExporter::AutoExporter() {
"_DllEntryPoint@12",
"_DllMainCRTStartup@12",
};
+ ExcludeSymbolPrefixes.insert("__head_");
} else {
ExcludeSymbols = {
- "_NULL_IMPORT_DESCRIPTOR",
+ "__NULL_IMPORT_DESCRIPTOR",
"_pei386_runtime_relocator",
"do_pseudo_reloc",
"impure_ptr",
@@ -52,8 +69,11 @@ AutoExporter::AutoExporter() {
"DllEntryPoint",
"DllMainCRTStartup",
};
+ ExcludeSymbolPrefixes.insert("_head_");
}
+}
+AutoExporter::AutoExporter() {
ExcludeLibs = {
"libgcc",
"libgcc_s",
@@ -64,6 +84,7 @@ AutoExporter::AutoExporter() {
"libsupc++",
"libobjc",
"libgcj",
+ "libclang_rt.builtins",
"libclang_rt.builtins-aarch64",
"libclang_rt.builtins-arm",
"libclang_rt.builtins-i386",
@@ -90,6 +111,13 @@ AutoExporter::AutoExporter() {
};
}
+void AutoExporter::addWholeArchive(StringRef Path) {
+ StringRef LibName = sys::path::filename(Path);
+ // Drop the file extension, to match the processing below.
+ LibName = LibName.substr(0, LibName.rfind('.'));
+ ExcludeLibs.erase(LibName);
+}
+
bool AutoExporter::shouldExport(Defined *Sym) const {
if (!Sym || !Sym->isLive() || !Sym->getChunk())
return false;
@@ -101,10 +129,12 @@ bool AutoExporter::shouldExport(Defined *Sym) const {
if (ExcludeSymbols.count(Sym->getName()))
return false;
- // Don't export anything that looks like an import symbol (which also can be
- // a manually defined data symbol with such a name).
- if (Sym->getName().startswith("__imp_"))
- return false;
+ for (StringRef Prefix : ExcludeSymbolPrefixes.keys())
+ if (Sym->getName().startswith(Prefix))
+ return false;
+ for (StringRef Suffix : ExcludeSymbolSuffixes.keys())
+ if (Sym->getName().endswith(Suffix))
+ return false;
// If a corresponding __imp_ symbol exists and is defined, don't export it.
if (Symtab->find(("__imp_" + Sym->getName()).str()))
diff --git a/COFF/MinGW.h b/COFF/MinGW.h
index fe6cc5588ebc..f9c5e3e5c2cc 100644
--- a/COFF/MinGW.h
+++ b/COFF/MinGW.h
@@ -23,7 +23,13 @@ class AutoExporter {
public:
AutoExporter();
+ void initSymbolExcludes();
+
+ void addWholeArchive(StringRef Path);
+
llvm::StringSet<> ExcludeSymbols;
+ llvm::StringSet<> ExcludeSymbolPrefixes;
+ llvm::StringSet<> ExcludeSymbolSuffixes;
llvm::StringSet<> ExcludeLibs;
llvm::StringSet<> ExcludeObjects;
diff --git a/COFF/Options.td b/COFF/Options.td
index 871bad8bd655..acf1bc5c8b1d 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -66,13 +66,18 @@ def wholearchive_file : P<"wholearchive", "Include all object files from this ar
def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
-def manifest : F<"manifest">;
-def manifest_colon : P<"manifest", "Create manifest file">;
+def manifest : F<"manifest">, HelpText<"Create .manifest file">;
+def manifest_colon : P<
+ "manifest",
+ "NO disables manifest output; EMBED[,ID=#] embeds manifest as resource in the image">;
def manifestuac : P<"manifestuac", "User access control">;
-def manifestfile : P<"manifestfile", "Manifest file path">;
-def manifestdependency : P<"manifestdependency",
- "Attributes for <dependency> in manifest file">;
-def manifestinput : P<"manifestinput", "Specify manifest file">;
+def manifestfile : P<"manifestfile", "Manifest output path, with /manifest">;
+def manifestdependency : P<
+ "manifestdependency",
+ "Attributes for <dependency> element in manifest file; implies /manifest">;
+def manifestinput : P<
+ "manifestinput",
+ "Additional manifest inputs; only valid with /manifest:embed">;
// We cannot use multiclass P because class name "incl" is different
// from its command line option name. We do this because "include" is
@@ -85,22 +90,28 @@ 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 debug_opt : P<"debug", "Embed a symbol table in the image with option">;
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 nodefaultlib_all : F<"nodefaultlib">,
+ HelpText<"Remove all default libraries">;
+def noentry : F<"noentry">,
+ HelpText<"Don't add reference to DllMainCRTStartup; only valid with /dll">;
def profile : F<"profile">;
-def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">;
+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">;
def wholearchive_flag : F<"wholearchive">;
def force : F<"force">,
+ HelpText<"Allow undefined and multiply defined symbols when creating executables">;
+def force_unresolved : F<"force:unresolved">,
HelpText<"Allow undefined symbols when creating executables">;
-def force_unresolved : F<"force:unresolved">;
+def force_multiple : F<"force:multiple">,
+ HelpText<"Allow multiply defined symbols when creating executables">;
defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">;
defm allowbind : B<"allowbind", "Enable DLL binding (default)",
@@ -139,13 +150,9 @@ def help : F<"help">;
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">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 766bf3f6b456..7862b6ce4cc5 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -16,12 +16,14 @@
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Timer.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/RecordName.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
@@ -48,8 +50,10 @@
#include "llvm/Object/CVDebugRecord.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JamCRC.h"
+#include "llvm/Support/Parallel.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>
@@ -79,9 +83,14 @@ struct CVIndexMap {
SmallVector<TypeIndex, 0> TPIMap;
SmallVector<TypeIndex, 0> IPIMap;
bool IsTypeServerMap = false;
+ bool IsPrecompiledTypeMap = false;
};
+class DebugSHandler;
+
class PDBLinker {
+ friend DebugSHandler;
+
public:
PDBLinker(SymbolTable *Symtab)
: Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc),
@@ -93,7 +102,7 @@ public:
}
/// Emit the basic PDB structure: initial streams, headers, etc.
- void initialize(const llvm::codeview::DebugInfo &BuildId);
+ void initialize(llvm::codeview::DebugInfo *BuildId);
/// Add natvis files specified on the command line.
void addNatvisFiles();
@@ -101,8 +110,10 @@ public:
/// Link CodeView from each object file in the symbol table into the PDB.
void addObjectsToPDB();
- /// Link CodeView from a single object file into the PDB.
- void addObjFile(ObjFile *File);
+ /// Link CodeView from a single object file into the target (output) PDB.
+ /// When a precompiled headers object is linked, its TPI map might be provided
+ /// externally.
+ void addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap = nullptr);
/// Produce a mapping from the type and item indices used in the object
/// file to those in the destination PDB.
@@ -115,18 +126,60 @@ 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.
- Expected<const CVIndexMap&> mergeDebugT(ObjFile *File,
- CVIndexMap &ObjectIndexMap);
+ Expected<const CVIndexMap &> mergeDebugT(ObjFile *File,
+ CVIndexMap *ObjectIndexMap);
+
+ /// Reads and makes available a PDB.
+ Expected<const CVIndexMap &> maybeMergeTypeServerPDB(ObjFile *File,
+ const CVType &FirstType);
+
+ /// Merges a precompiled headers TPI map into the current TPI map. The
+ /// precompiled headers object will also be loaded and remapped in the
+ /// process.
+ Expected<const CVIndexMap &>
+ mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType,
+ CVIndexMap *ObjectIndexMap);
+
+ /// Reads and makes available a precompiled headers object.
+ ///
+ /// This is a requirement for objects compiled with cl.exe /Yu. In that
+ /// case, the referenced object (which was compiled with /Yc) has to be loaded
+ /// first. This is mainly because the current object's TPI stream has external
+ /// references to the precompiled headers object.
+ ///
+ /// If the precompiled headers object was already loaded, this function will
+ /// simply return its (remapped) TPI map.
+ Expected<const CVIndexMap &> aquirePrecompObj(ObjFile *File,
+ PrecompRecord Precomp);
+
+ /// Adds a precompiled headers object signature -> TPI mapping.
+ std::pair<CVIndexMap &, bool /*already there*/>
+ registerPrecompiledHeaders(uint32_t Signature);
- Expected<const CVIndexMap&> maybeMergeTypeServerPDB(ObjFile *File,
- TypeServer2Record &TS);
+ void mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
+ std::vector<ulittle32_t *> &StringTableRefs,
+ BinaryStreamRef SymData);
/// Add the section map and section contributions to the PDB.
void addSections(ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable);
- /// Write the PDB to disk.
- void commit();
+ /// Get the type table or the global type table if /DEBUG:GHASH is enabled.
+ TypeCollection &getTypeTable() {
+ if (Config->DebugGHashes)
+ return GlobalTypeTable;
+ return TypeTable;
+ }
+
+ /// Get the ID table or the global ID table if /DEBUG:GHASH is enabled.
+ TypeCollection &getIDTable() {
+ if (Config->DebugGHashes)
+ return GlobalIDTable;
+ return IDTable;
+ }
+
+ /// Write the PDB to disk and store the Guid generated for it in *Guid.
+ void commit(codeview::GUID *Guid);
private:
BumpPtrAllocator Alloc;
@@ -161,14 +214,95 @@ private:
std::vector<pdb::SecMapEntry> SectionMap;
/// Type index mappings of type server PDBs that we've loaded so far.
- std::map<GUID, CVIndexMap> TypeServerIndexMappings;
+ std::map<codeview::GUID, CVIndexMap> TypeServerIndexMappings;
+
+ /// Type index mappings of precompiled objects type map that we've loaded so
+ /// far.
+ std::map<uint32_t, CVIndexMap> PrecompTypeIndexMappings;
/// List of TypeServer PDBs which cannot be loaded.
/// Cached to prevent repeated load attempts.
- std::set<GUID> MissingTypeServerPDBs;
+ std::map<codeview::GUID, std::string> MissingTypeServerPDBs;
+};
+
+class DebugSHandler {
+ PDBLinker &Linker;
+
+ /// The object file whose .debug$S sections we're processing.
+ ObjFile &File;
+
+ /// The result of merging type indices.
+ const CVIndexMap &IndexMap;
+
+ /// The DEBUG_S_STRINGTABLE subsection. These strings are referred to by
+ /// index from other records in the .debug$S section. All of these strings
+ /// need to be added to the global PDB string table, and all references to
+ /// these strings need to have their indices re-written to refer to the
+ /// global PDB string table.
+ DebugStringTableSubsectionRef CVStrTab;
+
+ /// The DEBUG_S_FILECHKSMS subsection. As above, these are referred to
+ /// by other records in the .debug$S section and need to be merged into the
+ /// PDB.
+ DebugChecksumsSubsectionRef Checksums;
+
+ /// The DEBUG_S_FRAMEDATA subsection(s). There can be more than one of
+ /// these and they need not appear in any specific order. However, they
+ /// contain string table references which need to be re-written, so we
+ /// collect them all here and re-write them after all subsections have been
+ /// discovered and processed.
+ std::vector<DebugFrameDataSubsectionRef> NewFpoFrames;
+
+ /// Pointers to raw memory that we determine have string table references
+ /// that need to be re-written. We first process all .debug$S subsections
+ /// to ensure that we can handle subsections written in any order, building
+ /// up this list as we go. At the end, we use the string table (which must
+ /// have been discovered by now else it is an error) to re-write these
+ /// references.
+ std::vector<ulittle32_t *> StringTableReferences;
+
+public:
+ DebugSHandler(PDBLinker &Linker, ObjFile &File, const CVIndexMap &IndexMap)
+ : Linker(Linker), File(File), IndexMap(IndexMap) {}
+
+ void handleDebugS(lld::coff::SectionChunk &DebugS);
+ void finish();
};
}
+// Visual Studio's debugger requires absolute paths in various places in the
+// PDB to work without additional configuration:
+// https://docs.microsoft.com/en-us/visualstudio/debugger/debug-source-files-common-properties-solution-property-pages-dialog-box
+static void pdbMakeAbsolute(SmallVectorImpl<char> &FileName) {
+ // The default behavior is to produce paths that are valid within the context
+ // of the machine that you perform the link on. If the linker is running on
+ // a POSIX system, we will output absolute POSIX paths. If the linker is
+ // running on a Windows system, we will output absolute Windows paths. If the
+ // user desires any other kind of behavior, they should explicitly pass
+ // /pdbsourcepath, in which case we will treat the exact string the user
+ // passed in as the gospel and not normalize, canonicalize it.
+ if (sys::path::is_absolute(FileName, sys::path::Style::windows) ||
+ sys::path::is_absolute(FileName, sys::path::Style::posix))
+ return;
+
+ // It's not absolute in any path syntax. Relative paths necessarily refer to
+ // the local file system, so we can make it native without ending up with a
+ // nonsensical path.
+ sys::path::native(FileName);
+ if (Config->PDBSourcePath.empty()) {
+ sys::fs::make_absolute(FileName);
+ return;
+ }
+ // Only apply native and dot removal to the relative file path. We want to
+ // leave the path the user specified untouched since we assume they specified
+ // it for a reason.
+ sys::path::remove_dots(FileName, /*remove_dot_dots=*/true);
+
+ SmallString<128> AbsoluteFileName = Config->PDBSourcePath;
+ sys::path::append(AbsoluteFileName, FileName);
+ FileName = std::move(AbsoluteFileName);
+}
+
static SectionChunk *findByName(ArrayRef<SectionChunk *> Sections,
StringRef Name) {
for (SectionChunk *C : Sections)
@@ -242,27 +376,79 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
});
}
-static Optional<TypeServer2Record>
-maybeReadTypeServerRecord(CVTypeArray &Types) {
- auto I = Types.begin();
- if (I == Types.end())
- return None;
- const CVType &Type = *I;
- if (Type.kind() != LF_TYPESERVER2)
- return None;
- TypeServer2Record TS;
- if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), TS))
- fatal("error reading type server record: " + toString(std::move(EC)));
- return std::move(TS);
+// OBJs usually start their symbol stream with a S_OBJNAME record. This record
+// also contains the signature/key of the current PCH session. The signature
+// must be same for all objects which depend on the precompiled object.
+// Recompiling the precompiled headers will generate a new PCH key and thus
+// invalidate all the dependent objects.
+static uint32_t extractPCHSignature(ObjFile *File) {
+ auto DbgIt = find_if(File->getDebugChunks(), [](SectionChunk *C) {
+ return C->getSectionName() == ".debug$S";
+ });
+ if (!DbgIt)
+ return 0;
+
+ ArrayRef<uint8_t> Contents =
+ consumeDebugMagic((*DbgIt)->getContents(), ".debug$S");
+ DebugSubsectionArray Subsections;
+ BinaryStreamReader Reader(Contents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, Contents.size()));
+
+ for (const DebugSubsectionRecord &SS : Subsections) {
+ if (SS.kind() != DebugSubsectionKind::Symbols)
+ continue;
+
+ // If it's there, the S_OBJNAME record shall come first in the stream.
+ Expected<CVSymbol> Sym = readSymbolFromStream(SS.getRecordData(), 0);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ continue;
+ }
+ if (auto ObjName = SymbolDeserializer::deserializeAs<ObjNameSym>(Sym.get()))
+ return ObjName->Signature;
+ }
+ return 0;
}
-Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File,
- CVIndexMap &ObjectIndexMap) {
+Expected<const CVIndexMap &>
+PDBLinker::mergeDebugT(ObjFile *File, CVIndexMap *ObjectIndexMap) {
ScopedTimer T(TypeMergingTimer);
+ bool IsPrecompiledHeader = false;
+
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
+ if (Data.empty()) {
+ // Try again, Microsoft precompiled headers use .debug$P instead of
+ // .debug$T
+ Data = getDebugSection(File, ".debug$P");
+ IsPrecompiledHeader = true;
+ }
if (Data.empty())
- return ObjectIndexMap;
+ return *ObjectIndexMap; // no debug info
+
+ // Precompiled headers objects need to save the index map for further
+ // reference by other objects which use the precompiled headers.
+ if (IsPrecompiledHeader) {
+ uint32_t PCHSignature = extractPCHSignature(File);
+ if (PCHSignature == 0)
+ fatal("No signature found for the precompiled headers OBJ (" +
+ File->getName() + ")");
+
+ // When a precompiled headers object comes first on the command-line, we
+ // update the mapping here. Otherwise, if an object referencing the
+ // precompiled headers object comes first, the mapping is created in
+ // aquirePrecompObj(), thus we would skip this block.
+ if (!ObjectIndexMap->IsPrecompiledTypeMap) {
+ auto R = registerPrecompiledHeaders(PCHSignature);
+ if (R.second)
+ fatal(
+ "A precompiled headers OBJ with the same signature was already "
+ "provided! (" +
+ File->getName() + ")");
+
+ ObjectIndexMap = &R.first;
+ }
+ }
BinaryByteStream Stream(Data, support::little);
CVTypeArray Types;
@@ -270,13 +456,32 @@ Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File,
if (auto EC = Reader.readArray(Types, Reader.getLength()))
fatal("Reader::readArray failed: " + toString(std::move(EC)));
- // Look through type servers. If we've already seen this type server, don't
- // merge any type information.
- if (Optional<TypeServer2Record> TS = maybeReadTypeServerRecord(Types))
- return maybeMergeTypeServerPDB(File, *TS);
+ auto FirstType = Types.begin();
+ if (FirstType == Types.end())
+ return *ObjectIndexMap;
+
+ if (FirstType->kind() == LF_TYPESERVER2) {
+ // Look through type servers. If we've already seen this type server,
+ // don't merge any type information.
+ return maybeMergeTypeServerPDB(File, *FirstType);
+ } else if (FirstType->kind() == LF_PRECOMP) {
+ // This object was compiled with /Yu, so process the corresponding
+ // precompiled headers object (/Yc) first. Some type indices in the current
+ // object are referencing data in the precompiled headers object, so we need
+ // both to be loaded.
+ auto E = mergeInPrecompHeaderObj(File, *FirstType, ObjectIndexMap);
+ if (!E)
+ return E.takeError();
+
+ // Drop LF_PRECOMP record from the input stream, as it needs to be replaced
+ // with the precompiled headers object type stream.
+ // Note that we can't just call Types.drop_front(), as we explicitly want to
+ // rebase the stream.
+ Types.setUnderlyingStream(
+ Types.getUnderlyingStream().drop_front(FirstType->RecordData.size()));
+ }
- // This is a /Z7 object. Fill in the temporary, caller-provided
- // ObjectIndexMap.
+ // Fill in the temporary, caller-provided ObjectIndexMap.
if (Config->DebugGHashes) {
ArrayRef<GloballyHashedType> Hashes;
std::vector<GloballyHashedType> OwnedHashes;
@@ -288,20 +493,28 @@ Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File,
}
if (auto Err = mergeTypeAndIdRecords(GlobalIDTable, GlobalTypeTable,
- ObjectIndexMap.TPIMap, Types, Hashes))
+ ObjectIndexMap->TPIMap, Types, Hashes,
+ File->PCHSignature))
fatal("codeview::mergeTypeAndIdRecords failed: " +
toString(std::move(Err)));
} else {
- if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable,
- ObjectIndexMap.TPIMap, Types))
+ if (auto Err =
+ mergeTypeAndIdRecords(IDTable, TypeTable, ObjectIndexMap->TPIMap,
+ Types, File->PCHSignature))
fatal("codeview::mergeTypeAndIdRecords failed: " +
toString(std::move(Err)));
}
- return ObjectIndexMap;
+ return *ObjectIndexMap;
}
static Expected<std::unique_ptr<pdb::NativeSession>>
-tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
+tryToLoadPDB(const codeview::GUID &GuidFromObj, StringRef TSPath) {
+ // Ensure the file exists before anything else. We want to return ENOENT,
+ // "file not found", even if the path points to a removable device (in which
+ // case the return message would be EAGAIN, "resource unavailable try again")
+ if (!llvm::sys::fs::exists(TSPath))
+ return errorCodeToError(std::error_code(ENOENT, std::generic_category()));
+
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(
TSPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false);
if (!MBOrErr)
@@ -326,21 +539,27 @@ tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) {
// PDB file doesn't mean it matches. For it to match the InfoStream's GUID
// must match the GUID specified in the TypeServer2 record.
if (ExpectedInfo->getGuid() != GuidFromObj)
- return make_error<pdb::GenericError>(
- pdb::generic_error_code::type_server_not_found, TSPath);
+ return make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date);
return std::move(NS);
}
-Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
- TypeServer2Record &TS) {
- const GUID& TSId = TS.getGuid();
+Expected<const CVIndexMap &>
+PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, const CVType &FirstType) {
+ TypeServer2Record TS;
+ if (auto EC =
+ TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType), TS))
+ fatal("error reading record: " + toString(std::move(EC)));
+
+ const codeview::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);
+ auto PrevErr = MissingTypeServerPDBs.find(TSId);
+ if (PrevErr != MissingTypeServerPDBs.end())
+ return createFileError(
+ TSPath,
+ make_error<StringError>(PrevErr->second, inconvertibleErrorCode()));
// Second, check if we already loaded a PDB with this GUID. Return the type
// index mapping if we have it.
@@ -355,20 +574,39 @@ Expected<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(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(TSPath, sys::path::Style::windows));
- ExpectedSession = tryToLoadPDB(TSId, Path);
- }
+ auto ExpectedSession = handleExpected(
+ tryToLoadPDB(TSId, TSPath),
+ [&]() {
+ StringRef LocalPath =
+ !File->ParentName.empty() ? File->ParentName : File->getName();
+ SmallString<128> Path = sys::path::parent_path(LocalPath);
+ // Currently, type server PDBs are only created by cl, which only runs
+ // on Windows, so we can assume type server paths are Windows style.
+ sys::path::append(
+ Path, sys::path::filename(TSPath, sys::path::Style::windows));
+ return tryToLoadPDB(TSId, Path);
+ },
+ [&](std::unique_ptr<ECError> EC) -> Error {
+ auto SysErr = EC->convertToErrorCode();
+ // Only re-try loading if the previous error was "No such file or
+ // directory"
+ if (SysErr.category() == std::generic_category() &&
+ SysErr.value() == ENOENT)
+ return Error::success();
+ return Error(std::move(EC));
+ });
+
if (auto E = ExpectedSession.takeError()) {
TypeServerIndexMappings.erase(TSId);
- MissingTypeServerPDBs.emplace(TSId);
- return std::move(E);
+
+ // Flatten the error to a string, for later display, if the error occurs
+ // again on the same PDB.
+ std::string ErrMsg;
+ raw_string_ostream S(ErrMsg);
+ S << E;
+ MissingTypeServerPDBs.emplace(TSId, S.str());
+
+ return createFileError(TSPath, std::move(E));
}
pdb::NativeSession *Session = ExpectedSession->get();
@@ -394,9 +632,10 @@ Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
auto IpiHashes =
GloballyHashedType::hashIds(ExpectedIpi->typeArray(), TpiHashes);
+ Optional<uint32_t> EndPrecomp;
// Merge TPI first, because the IPI stream will reference type indices.
if (auto Err = mergeTypeRecords(GlobalTypeTable, IndexMap.TPIMap,
- ExpectedTpi->typeArray(), TpiHashes))
+ ExpectedTpi->typeArray(), TpiHashes, EndPrecomp))
fatal("codeview::mergeTypeRecords failed: " + toString(std::move(Err)));
// Merge IPI.
@@ -419,6 +658,103 @@ Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File,
return IndexMap;
}
+Expected<const CVIndexMap &>
+PDBLinker::mergeInPrecompHeaderObj(ObjFile *File, const CVType &FirstType,
+ CVIndexMap *ObjectIndexMap) {
+ PrecompRecord Precomp;
+ if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(FirstType),
+ Precomp))
+ fatal("error reading record: " + toString(std::move(EC)));
+
+ auto E = aquirePrecompObj(File, Precomp);
+ if (!E)
+ return E.takeError();
+
+ const CVIndexMap &PrecompIndexMap = *E;
+ assert(PrecompIndexMap.IsPrecompiledTypeMap);
+
+ if (PrecompIndexMap.TPIMap.empty())
+ return PrecompIndexMap;
+
+ assert(Precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
+ assert(Precomp.getTypesCount() <= PrecompIndexMap.TPIMap.size());
+ // Use the previously remapped index map from the precompiled headers.
+ ObjectIndexMap->TPIMap.append(PrecompIndexMap.TPIMap.begin(),
+ PrecompIndexMap.TPIMap.begin() +
+ Precomp.getTypesCount());
+ return *ObjectIndexMap;
+}
+
+static bool equals_path(StringRef path1, StringRef path2) {
+#if defined(_WIN32)
+ return path1.equals_lower(path2);
+#else
+ return path1.equals(path2);
+#endif
+}
+
+// Find by name an OBJ provided on the command line
+static ObjFile *findObjByName(StringRef FileNameOnly) {
+ SmallString<128> CurrentPath;
+
+ for (ObjFile *F : ObjFile::Instances) {
+ StringRef CurrentFileName = sys::path::filename(F->getName());
+
+ // Compare based solely on the file name (link.exe behavior)
+ if (equals_path(CurrentFileName, FileNameOnly))
+ return F;
+ }
+ return nullptr;
+}
+
+std::pair<CVIndexMap &, bool /*already there*/>
+PDBLinker::registerPrecompiledHeaders(uint32_t Signature) {
+ auto Insertion = PrecompTypeIndexMappings.insert({Signature, CVIndexMap()});
+ CVIndexMap &IndexMap = Insertion.first->second;
+ if (!Insertion.second)
+ return {IndexMap, true};
+ // Mark this map as a precompiled types map.
+ IndexMap.IsPrecompiledTypeMap = true;
+ return {IndexMap, false};
+}
+
+Expected<const CVIndexMap &>
+PDBLinker::aquirePrecompObj(ObjFile *File, PrecompRecord Precomp) {
+ // First, check if we already loaded the precompiled headers object with this
+ // signature. Return the type index mapping if we've already seen it.
+ auto R = registerPrecompiledHeaders(Precomp.getSignature());
+ if (R.second)
+ return R.first;
+
+ CVIndexMap &IndexMap = R.first;
+
+ // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
+ // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
+ // the paths embedded in the OBJs are in the Windows format.
+ SmallString<128> PrecompFileName = sys::path::filename(
+ Precomp.getPrecompFilePath(), sys::path::Style::windows);
+
+ // link.exe requires that a precompiled headers object must always be provided
+ // on the command-line, even if that's not necessary.
+ auto PrecompFile = findObjByName(PrecompFileName);
+ if (!PrecompFile)
+ return createFileError(
+ PrecompFileName.str(),
+ make_error<pdb::PDBError>(pdb::pdb_error_code::external_cmdline_ref));
+
+ addObjFile(PrecompFile, &IndexMap);
+
+ if (!PrecompFile->PCHSignature)
+ fatal(PrecompFile->getName() + " is not a precompiled headers object");
+
+ if (Precomp.getSignature() != PrecompFile->PCHSignature.getValueOr(0))
+ return createFileError(
+ Precomp.getPrecompFilePath().str(),
+ make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
+
+ return IndexMap;
+}
+
static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
if (TI.isSimple())
return true;
@@ -429,9 +765,11 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) {
}
static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind,
- MutableArrayRef<uint8_t> Contents,
+ MutableArrayRef<uint8_t> RecordBytes,
const CVIndexMap &IndexMap,
ArrayRef<TiReference> TypeRefs) {
+ MutableArrayRef<uint8_t> Contents =
+ RecordBytes.drop_front(sizeof(RecordPrefix));
for (const TiReference &Ref : TypeRefs) {
unsigned ByteSize = Ref.Count * sizeof(TypeIndex);
if (Contents.size() < Ref.Offset + ByteSize)
@@ -477,7 +815,7 @@ recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents,
switch (Kind) {
case SymbolKind::S_FILESTATIC:
// FileStaticSym::ModFileOffset
- recordStringTableReferenceAtOffset(Contents, 4, StrTableRefs);
+ recordStringTableReferenceAtOffset(Contents, 8, StrTableRefs);
break;
case SymbolKind::S_DEFRANGE:
case SymbolKind::S_DEFRANGE_SUBFIELD:
@@ -542,58 +880,26 @@ static void translateIdSymbols(MutableArrayRef<uint8_t> &RecordData,
/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned.
/// The object file may not be aligned.
-static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym,
- BumpPtrAllocator &Alloc) {
+static MutableArrayRef<uint8_t>
+copyAndAlignSymbol(const CVSymbol &Sym, MutableArrayRef<uint8_t> &AlignedMem) {
size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
assert(Size >= 4 && "record too short");
assert(Size <= MaxRecordLength && "record too long");
- void *Mem = Alloc.Allocate(Size, 4);
+ assert(AlignedMem.size() >= Size && "didn't preallocate enough");
// Copy the symbol record and zero out any padding bytes.
- MutableArrayRef<uint8_t> NewData(reinterpret_cast<uint8_t *>(Mem), Size);
+ MutableArrayRef<uint8_t> NewData = AlignedMem.take_front(Size);
+ AlignedMem = AlignedMem.drop_front(Size);
memcpy(NewData.data(), Sym.data().data(), Sym.length());
memset(NewData.data() + Sym.length(), 0, Size - Sym.length());
// Update the record prefix length. It should point to the beginning of the
// next record.
- auto *Prefix = reinterpret_cast<RecordPrefix *>(Mem);
+ auto *Prefix = reinterpret_cast<RecordPrefix *>(NewData.data());
Prefix->RecordLen = Size - 2;
return NewData;
}
-/// Return true if this symbol opens a scope. This implies that the symbol has
-/// "parent" and "end" fields, which contain the offset of the S_END or
-/// S_INLINESITE_END record.
-static bool symbolOpensScope(SymbolKind Kind) {
- switch (Kind) {
- case SymbolKind::S_GPROC32:
- case SymbolKind::S_LPROC32:
- case SymbolKind::S_LPROC32_ID:
- case SymbolKind::S_GPROC32_ID:
- case SymbolKind::S_BLOCK32:
- case SymbolKind::S_SEPCODE:
- case SymbolKind::S_THUNK32:
- case SymbolKind::S_INLINESITE:
- case SymbolKind::S_INLINESITE2:
- return true;
- default:
- break;
- }
- return false;
-}
-
-static bool symbolEndsScope(SymbolKind Kind) {
- switch (Kind) {
- case SymbolKind::S_END:
- case SymbolKind::S_PROC_ID_END:
- case SymbolKind::S_INLINESITE_END:
- return true;
- default:
- break;
- }
- return false;
-}
-
struct ScopeRecord {
ulittle32_t PtrParent;
ulittle32_t PtrEnd;
@@ -625,11 +931,10 @@ static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
S.OpeningRecord->PtrEnd = CurOffset;
}
-static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
+static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) {
switch (Sym.kind()) {
case SymbolKind::S_GDATA32:
case SymbolKind::S_CONSTANT:
- case SymbolKind::S_UDT:
// We really should not be seeing S_PROCREF and S_LPROCREF in the first place
// since they are synthesized by the linker in response to S_GPROC32 and
// S_LPROC32, but if we do see them, don't put them in the module stream I
@@ -637,6 +942,9 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
case SymbolKind::S_PROCREF:
case SymbolKind::S_LPROCREF:
return false;
+ // S_UDT records go in the module stream if it is not a global S_UDT.
+ case SymbolKind::S_UDT:
+ return !IsGlobalScope;
// S_GDATA32 does not go in the module stream, but S_LDATA32 does.
case SymbolKind::S_LDATA32:
default:
@@ -644,7 +952,7 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
}
}
-static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) {
+static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) {
switch (Sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_GDATA32:
@@ -658,20 +966,16 @@ static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) {
case SymbolKind::S_PROCREF:
case SymbolKind::S_LPROCREF:
return true;
- // FIXME: For now, we drop all S_UDT symbols (i.e. they don't go in the
- // globals stream or the modules stream). These have special handling which
- // needs more investigation before we can get right, but by putting them all
- // into the globals stream WinDbg fails to display local variables of class
- // types saying that it cannot find the type Foo *. So as a stopgap just to
- // keep things working, we drop them.
+ // S_UDT records go in the globals stream if it is a global S_UDT.
case SymbolKind::S_UDT:
+ return IsGlobalScope;
default:
return false;
}
}
-static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File,
- const CVSymbol &Sym) {
+static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, uint16_t ModIndex,
+ unsigned SymOffset, const CVSymbol &Sym) {
switch (Sym.kind()) {
case SymbolKind::S_CONSTANT:
case SymbolKind::S_UDT:
@@ -687,12 +991,12 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File,
if (Sym.kind() == SymbolKind::S_LPROC32)
K = SymbolRecordKind::LocalProcRef;
ProcRefSym PS(K);
- PS.Module = static_cast<uint16_t>(File.ModuleDBI->getModuleIndex());
+ PS.Module = ModIndex;
// For some reason, MSVC seems to add one to this value.
++PS.Module;
PS.Name = getSymbolName(Sym);
PS.SumName = 0;
- PS.SymOffset = File.ModuleDBI->getNextSymbolOffset();
+ PS.SymOffset = SymOffset;
Builder.addGlobalSymbol(PS);
break;
}
@@ -701,20 +1005,62 @@ static void addGlobalSymbol(pdb::GSIStreamBuilder &Builder, ObjFile &File,
}
}
-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.
+void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
+ std::vector<ulittle32_t *> &StringTableRefs,
+ BinaryStreamRef SymData) {
ArrayRef<uint8_t> SymsBuffer;
cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
SmallVector<SymbolScope, 4> Scopes;
+ // Iterate every symbol to check if any need to be realigned, and if so, how
+ // much space we need to allocate for them.
+ bool NeedsRealignment = false;
+ unsigned TotalRealignedSize = 0;
auto EC = forEachCodeViewRecord<CVSymbol>(
- SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
+ SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
+ unsigned RealignedSize =
+ alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb));
+ NeedsRealignment |= RealignedSize != Sym.length();
+ TotalRealignedSize += RealignedSize;
+ return Error::success();
+ });
+
+ // If any of the symbol record lengths was corrupt, ignore them all, warn
+ // about it, and move on.
+ if (EC) {
+ warn("corrupt symbol records in " + File->getName());
+ consumeError(std::move(EC));
+ return;
+ }
+
+ // If any symbol needed realignment, allocate enough contiguous memory for
+ // them all. Typically symbol subsections are small enough that this will not
+ // cause fragmentation.
+ MutableArrayRef<uint8_t> AlignedSymbolMem;
+ if (NeedsRealignment) {
+ void *AlignedData =
+ Alloc.Allocate(TotalRealignedSize, alignOf(CodeViewContainer::Pdb));
+ AlignedSymbolMem = makeMutableArrayRef(
+ reinterpret_cast<uint8_t *>(AlignedData), TotalRealignedSize);
+ }
+
+ // Iterate again, this time doing the real work.
+ unsigned CurSymOffset = File->ModuleDBI->getNextSymbolOffset();
+ ArrayRef<uint8_t> BulkSymbols;
+ cantFail(forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](CVSymbol Sym) -> llvm::Error {
+ // Align the record if required.
+ MutableArrayRef<uint8_t> RecordBytes;
+ if (NeedsRealignment) {
+ RecordBytes = copyAndAlignSymbol(Sym, AlignedSymbolMem);
+ Sym = CVSymbol(Sym.kind(), RecordBytes);
+ } else {
+ // Otherwise, we can actually mutate the symbol directly, since we
+ // copied it to apply relocations.
+ RecordBytes = makeMutableArrayRef(
+ const_cast<uint8_t *>(Sym.data().data()), Sym.length());
+ }
+
// Discover type index references in the record. Skip it if we don't
// know where they are.
SmallVector<TiReference, 32> TypeRefs;
@@ -724,57 +1070,62 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File,
return Error::success();
}
- // 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,
+ remapTypesInSymbolRecord(File, Sym.kind(), RecordBytes, IndexMap,
TypeRefs);
// An object file may have S_xxx_ID symbols, but these get converted to
// "real" symbols in a PDB.
- translateIdSymbols(NewData, IDTable);
+ translateIdSymbols(RecordBytes, getIDTable());
+ Sym = CVSymbol(symbolKind(RecordBytes), RecordBytes);
// 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);
+ recordStringTableReferences(Sym.kind(), RecordBytes, StringTableRefs);
// 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);
+ if (symbolOpensScope(Sym.kind()))
+ scopeStackOpen(Scopes, CurSymOffset, Sym);
+ else if (symbolEndsScope(Sym.kind()))
+ scopeStackClose(Scopes, CurSymOffset, 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);
+ if (symbolGoesInGlobalsStream(Sym, Scopes.empty()))
+ addGlobalSymbol(Builder.getGsiBuilder(),
+ File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym);
+
+ if (symbolGoesInModuleStream(Sym, Scopes.empty())) {
+ // Add symbols to the module in bulk. If this symbol is contiguous
+ // with the previous run of symbols to add, combine the ranges. If
+ // not, close the previous range of symbols and start a new one.
+ if (Sym.data().data() == BulkSymbols.end()) {
+ BulkSymbols = makeArrayRef(BulkSymbols.data(),
+ BulkSymbols.size() + Sym.length());
+ } else {
+ File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
+ BulkSymbols = RecordBytes;
+ }
+ CurSymOffset += Sym.length();
+ }
return Error::success();
- });
- cantFail(std::move(EC));
+ }));
+
+ // Add any remaining symbols we've accumulated.
+ File->ModuleDBI->addSymbolsInBulk(BulkSymbols);
}
-// Allocate memory for a .debug$S section and relocate it.
+// Allocate memory for a .debug$S / .debug$F section and relocate it.
static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc,
- SectionChunk *DebugChunk) {
- uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk->getSize());
- assert(DebugChunk->OutputSectionOff == 0 &&
+ SectionChunk &DebugChunk) {
+ uint8_t *Buffer = Alloc.Allocate<uint8_t>(DebugChunk.getSize());
+ assert(DebugChunk.OutputSectionOff == 0 &&
"debug sections should not be in output sections");
- DebugChunk->writeTo(Buffer);
- return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()),
- ".debug$S");
+ DebugChunk.readRelocTargets();
+ DebugChunk.writeTo(Buffer);
+ return makeArrayRef(Buffer, DebugChunk.getSize());
}
static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
@@ -803,25 +1154,137 @@ static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) {
return SC;
}
-void PDBLinker::addObjFile(ObjFile *File) {
+static uint32_t
+translateStringTableIndex(uint32_t ObjIndex,
+ const DebugStringTableSubsectionRef &ObjStrTable,
+ DebugStringTableSubsection &PdbStrTable) {
+ auto ExpectedString = ObjStrTable.getString(ObjIndex);
+ if (!ExpectedString) {
+ warn("Invalid string table reference");
+ consumeError(ExpectedString.takeError());
+ return 0;
+ }
+
+ return PdbStrTable.insert(*ExpectedString);
+}
+
+void DebugSHandler::handleDebugS(lld::coff::SectionChunk &DebugS) {
+ DebugSubsectionArray Subsections;
+
+ ArrayRef<uint8_t> RelocatedDebugContents = consumeDebugMagic(
+ relocateDebugChunk(Linker.Alloc, DebugS), DebugS.getSectionName());
+
+ BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+ ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.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:
+ // We can add the relocated line table directly to the PDB without
+ // modification because the file checksum offsets will stay the same.
+ File.ModuleDBI->addDebugSubsection(SS);
+ break;
+ case DebugSubsectionKind::FrameData: {
+ // We need to re-write string table indices here, so save off all
+ // frame data subsections until we've processed the entire list of
+ // subsections so that we can be sure we have the string table.
+ DebugFrameDataSubsectionRef FDS;
+ ExitOnErr(FDS.initialize(SS.getRecordData()));
+ NewFpoFrames.push_back(std::move(FDS));
+ break;
+ }
+ case DebugSubsectionKind::Symbols: {
+ Linker.mergeSymbolRecords(&File, IndexMap, StringTableReferences,
+ SS.getRecordData());
+ break;
+ }
+ default:
+ // FIXME: Process the rest of the subsections.
+ break;
+ }
+ }
+}
+
+void DebugSHandler::finish() {
+ pdb::DbiStreamBuilder &DbiBuilder = Linker.Builder.getDbiBuilder();
+
+ // 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 string table indices in the Fpo Data and symbol records to refer to
+ // the global PDB string table instead of the object file string table.
+ for (DebugFrameDataSubsectionRef &FDS : NewFpoFrames) {
+ const ulittle32_t *Reloc = FDS.getRelocPtr();
+ for (codeview::FrameData FD : FDS) {
+ FD.RvaStart += *Reloc;
+ FD.FrameFunc =
+ translateStringTableIndex(FD.FrameFunc, CVStrTab, Linker.PDBStrTab);
+ DbiBuilder.addNewFpoData(FD);
+ }
+ }
+
+ for (ulittle32_t *Ref : StringTableReferences)
+ *Ref = translateStringTableIndex(*Ref, CVStrTab, Linker.PDBStrTab);
+
+ // 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>(Linker.PDBStrTab);
+ for (FileChecksumEntry &FC : Checksums) {
+ SmallString<128> FileName =
+ ExitOnErr(CVStrTab.getString(FC.FileNameOffset));
+ pdbMakeAbsolute(FileName);
+ ExitOnErr(Linker.Builder.getDbiBuilder().addModuleSourceFile(
+ *File.ModuleDBI, FileName));
+ NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum);
+ }
+ File.ModuleDBI->addDebugSubsection(std::move(NewChecksums));
+}
+
+void PDBLinker::addObjFile(ObjFile *File, CVIndexMap *ExternIndexMap) {
+ if (File->wasProcessedForPDB())
+ return;
// Add a module descriptor for every object file. We need to put an absolute
// path to the object into the PDB. If this is a plain object, we make its
// path absolute. If it's an object in an archive, we make the archive path
// absolute.
bool InArchive = !File->ParentName.empty();
SmallString<128> Path = InArchive ? File->ParentName : File->getName();
- sys::fs::make_absolute(Path);
- sys::path::native(Path, sys::path::Style::windows);
+ pdbMakeAbsolute(Path);
StringRef Name = InArchive ? File->getName() : StringRef(Path);
- File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name));
+ pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
+ File->ModuleDBI = &ExitOnErr(DbiBuilder.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())
+ if (!SecChunk || !SecChunk->Live)
continue;
pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi);
File->ModuleDBI->setFirstSectionContrib(SC);
@@ -833,119 +1296,54 @@ void PDBLinker::addObjFile(ObjFile *File) {
// 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;
- auto IndexMapResult = mergeDebugT(File, ObjectIndexMap);
+ auto IndexMapResult =
+ mergeDebugT(File, ExternIndexMap ? ExternIndexMap : &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()));
+ if (!Config->WarnDebugInfoUnusable) {
+ consumeError(IndexMapResult.takeError());
+ return;
+ }
+ StringRef FileName = sys::path::filename(Path);
+ warn("Cannot use debug info for '" + FileName + "' [LNK4099]\n" +
+ ">>> failed to load reference " +
+ StringRef(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;
+ DebugSHandler DSH(*this, *File, *IndexMapResult);
+ // Now do all live .debug$S and .debug$F sections.
for (SectionChunk *DebugChunk : File->getDebugChunks()) {
- if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S")
+ if (!DebugChunk->Live || DebugChunk->getSize() == 0)
continue;
- ArrayRef<uint8_t> RelocatedDebugContents =
- relocateDebugChunk(Alloc, DebugChunk);
- if (RelocatedDebugContents.empty())
+ if (DebugChunk->getSectionName() == ".debug$S") {
+ DSH.handleDebugS(*DebugChunk);
continue;
-
- DebugSubsectionArray Subsections;
- BinaryStreamReader Reader(RelocatedDebugContents, support::little);
- ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.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:
- // We can add the relocated line table directly to the PDB without
- // modification because the file checksum offsets will stay the same.
- File->ModuleDBI->addDebugSubsection(SS);
- break;
- case DebugSubsectionKind::Symbols:
- if (Config->DebugGHashes) {
- mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- GlobalIDTable, StringTableReferences,
- SS.getRecordData());
- } else {
- mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap,
- IDTable, StringTableReferences,
- SS.getRecordData());
- }
- break;
- default:
- // FIXME: Process the rest of the subsections.
- 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 (DebugChunk->getSectionName() == ".debug$F") {
+ ArrayRef<uint8_t> RelocatedDebugContents =
+ relocateDebugChunk(Alloc, *DebugChunk);
- if (!StringTableReferences.empty())
- warn("No StringTable subsection was encountered, but there are string "
- "table references");
- return;
- }
+ FixedStreamArray<object::FpoData> FpoRecords;
+ BinaryStreamReader Reader(RelocatedDebugContents, support::little);
+ uint32_t Count = RelocatedDebugContents.size() / sizeof(object::FpoData);
+ ExitOnErr(Reader.readArray(FpoRecords, Count));
- // 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());
+ // These are already relocated and don't refer to the string table, so we
+ // can just copy it.
+ for (const object::FpoData &FD : FpoRecords)
+ DbiBuilder.addOldFpoData(FD);
continue;
}
-
- *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));
+ // Do any post-processing now that all .debug$S sections have been processed.
+ DSH.finish();
}
static PublicSym32 createPublic(Defined *Def) {
@@ -977,13 +1375,8 @@ void PDBLinker::addObjectsToPDB() {
// Construct TPI and IPI stream contents.
ScopedTimer T2(TpiStreamLayoutTimer);
- if (Config->DebugGHashes) {
- addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable);
- addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable);
- } else {
- addTypeInfo(Builder.getTpiBuilder(), TypeTable);
- addTypeInfo(Builder.getIpiBuilder(), IDTable);
- }
+ addTypeInfo(Builder.getTpiBuilder(), getTypeTable());
+ addTypeInfo(Builder.getIpiBuilder(), getIDTable());
T2.stop();
ScopedTimer T3(GlobalsLayoutTimer);
@@ -999,10 +1392,10 @@ void PDBLinker::addObjectsToPDB() {
if (!Publics.empty()) {
// Sort the public symbols and add them to the stream.
- std::sort(Publics.begin(), Publics.end(),
- [](const PublicSym32 &L, const PublicSym32 &R) {
- return L.Name < R.Name;
- });
+ sort(parallel::par, Publics.begin(), Publics.end(),
+ [](const PublicSym32 &L, const PublicSym32 &R) {
+ return L.Name < R.Name;
+ });
for (const PublicSym32 &Pub : Publics)
GsiBuilder.addPublicSymbol(Pub);
}
@@ -1037,6 +1430,32 @@ static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) {
}
}
+// Mimic MSVC which surrounds arguments containing whitespace with quotes.
+// Double double-quotes are handled, so that the resulting string can be
+// executed again on the cmd-line.
+static std::string quote(ArrayRef<StringRef> Args) {
+ std::string R;
+ R.reserve(256);
+ for (StringRef A : Args) {
+ if (!R.empty())
+ R.push_back(' ');
+ bool HasWS = A.find(' ') != StringRef::npos;
+ bool HasQ = A.find('"') != StringRef::npos;
+ if (HasWS || HasQ)
+ R.push_back('"');
+ if (HasQ) {
+ SmallVector<StringRef, 4> S;
+ A.split(S, '"');
+ R.append(join(S, "\"\""));
+ } else {
+ R.append(A);
+ }
+ if (HasWS || HasQ)
+ R.push_back('"');
+ }
+ return R;
+}
+
static void addCommonLinkerModuleSymbols(StringRef Path,
pdb::DbiModuleDescriptorBuilder &Mod,
BumpPtrAllocator &Allocator) {
@@ -1072,14 +1491,17 @@ static void addCommonLinkerModuleSymbols(StringRef Path,
CS.setLanguage(SourceLanguage::Link);
ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front();
- std::string ArgStr = llvm::join(Args, " ");
+ std::string ArgStr = quote(Args);
EBS.Fields.push_back("cwd");
SmallString<64> cwd;
- sys::fs::current_path(cwd);
+ if (Config->PDBSourcePath.empty())
+ sys::fs::current_path(cwd);
+ else
+ cwd = Config->PDBSourcePath;
EBS.Fields.push_back(cwd);
EBS.Fields.push_back("exe");
SmallString<64> exe = Config->Argv[0];
- llvm::sys::fs::make_absolute(exe);
+ pdbMakeAbsolute(exe);
EBS.Fields.push_back(exe);
EBS.Fields.push_back("pdb");
EBS.Fields.push_back(Path);
@@ -1111,7 +1533,7 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod,
void coff::createPDB(SymbolTable *Symtab,
ArrayRef<OutputSection *> OutputSections,
ArrayRef<uint8_t> SectionTable,
- const llvm::codeview::DebugInfo &BuildId) {
+ llvm::codeview::DebugInfo *BuildId) {
ScopedTimer T1(TotalPdbLinkTimer);
PDBLinker PDB(Symtab);
@@ -1121,12 +1543,19 @@ void coff::createPDB(SymbolTable *Symtab,
PDB.addNatvisFiles();
ScopedTimer T2(DiskCommitTimer);
- PDB.commit();
+ codeview::GUID Guid;
+ PDB.commit(&Guid);
+ memcpy(&BuildId->PDB70.Signature, &Guid, 16);
}
-void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) {
+void PDBLinker::initialize(llvm::codeview::DebugInfo *BuildId) {
ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize
+ BuildId->Signature.CVSignature = OMF::Signature::PDB70;
+ // Signature is set to a hash of the PDB contents when the PDB is done.
+ memset(BuildId->PDB70.Signature, 0, 16);
+ BuildId->PDB70.Age = 1;
+
// Create streams in MSF for predefined streams, namely
// PDB, TPI, DBI and IPI.
for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I)
@@ -1134,15 +1563,12 @@ void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) {
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
- GUID uuid;
- memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid));
- InfoBuilder.setAge(BuildId.PDB70.Age);
- InfoBuilder.setGuid(uuid);
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
+ InfoBuilder.setHashPDBContentsToGUID(true);
// Add an empty DBI stream.
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
- DbiBuilder.setAge(BuildId.PDB70.Age);
+ DbiBuilder.setAge(BuildId->PDB70.Age);
DbiBuilder.setVersionHeader(pdb::PdbDbiV70);
DbiBuilder.setMachineType(Config->Machine);
// Technically we are not link.exe 14.11, but there are known cases where
@@ -1157,8 +1583,7 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
// It's not entirely clear what this is, but the * Linker * module uses it.
pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder();
NativePath = Config->PDBPath;
- sys::fs::make_absolute(NativePath);
- sys::path::native(NativePath, sys::path::Style::windows);
+ pdbMakeAbsolute(NativePath);
uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath);
auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
LinkerModule.setPdbFilePathNI(PdbFilePathNI);
@@ -1167,7 +1592,7 @@ 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()) {
+ for (Chunk *C : OS->Chunks) {
pdb::SectionContrib SC =
createSectionContrib(C, LinkerModule.getModuleIndex());
Builder.getDbiBuilder().addSectionContrib(SC);
@@ -1186,9 +1611,9 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections,
DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable));
}
-void PDBLinker::commit() {
+void PDBLinker::commit(codeview::GUID *Guid) {
// Write to a file.
- ExitOnErr(Builder.commit(Config->PDBPath));
+ ExitOnErr(Builder.commit(Config->PDBPath, Guid));
}
static Expected<StringRef>
@@ -1315,20 +1740,26 @@ std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C,
if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable))
return {"", 0};
- uint32_t NameIndex;
- uint32_t LineNumber;
+ Optional<uint32_t> NameIndex;
+ Optional<uint32_t> LineNumber;
for (LineColumnEntry &Entry : Lines) {
for (const LineNumberEntry &LN : Entry.LineNumbers) {
+ LineInfo LI(LN.Flags);
if (LN.Offset > OffsetInLinetable) {
+ if (!NameIndex) {
+ NameIndex = Entry.NameIndex;
+ LineNumber = LI.getStartLine();
+ }
StringRef Filename =
- ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex));
- return {Filename, LineNumber};
+ 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};
+ if (!NameIndex)
+ return {"", 0};
+ StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, *NameIndex));
+ return {Filename, *LineNumber};
}
diff --git a/COFF/PDB.h b/COFF/PDB.h
index a98d129a633b..ea7a9996f415 100644
--- a/COFF/PDB.h
+++ b/COFF/PDB.h
@@ -28,7 +28,7 @@ class SymbolTable;
void createPDB(SymbolTable *Symtab,
llvm::ArrayRef<OutputSection *> OutputSections,
llvm::ArrayRef<uint8_t> SectionTable,
- const llvm::codeview::DebugInfo &BuildId);
+ llvm::codeview::DebugInfo *BuildId);
std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C,
uint32_t Addr);
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index b286d865caaf..1a9e0455dc1d 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -60,16 +60,16 @@ void SymbolTable::addFile(InputFile *File) {
}
static void errorOrWarn(const Twine &S) {
- if (Config->Force)
+ if (Config->ForceUnresolved)
warn(S);
else
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) {
+// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
+// This is generally the global variable or function whose definition contains
+// Addr.
+static Symbol *getSymbol(SectionChunk *SC, uint32_t Addr) {
DefinedRegular *Candidate = nullptr;
for (Symbol *S : SC->File->getSymbols()) {
@@ -81,14 +81,12 @@ static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) {
Candidate = D;
}
- if (!Candidate)
- return "";
- return Candidate->getName();
+ return Candidate;
}
-static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
+std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
struct Location {
- StringRef SymName;
+ Symbol *Sym;
std::pair<StringRef, uint32_t> FileLine;
};
std::vector<Location> Locations;
@@ -102,14 +100,14 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t 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});
+ Symbol *Sym = getSymbol(SC, R.VirtualAddress);
+ if (!FileLine.first.empty() || Sym)
+ Locations.push_back({Sym, FileLine});
}
}
if (Locations.empty())
- return "\n>>> referenced by " + toString(File) + "\n";
+ return "\n>>> referenced by " + toString(File);
std::string Out;
llvm::raw_string_ostream OS(Out);
@@ -119,13 +117,87 @@ static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) {
OS << Loc.FileLine.first << ":" << Loc.FileLine.second
<< "\n>>> ";
OS << toString(File);
- if (!Loc.SymName.empty())
- OS << ":(" << Loc.SymName << ')';
+ if (Loc.Sym)
+ OS << ":(" << toString(*Loc.Sym) << ')';
}
- OS << '\n';
return OS.str();
}
+void SymbolTable::loadMinGWAutomaticImports() {
+ for (auto &I : SymMap) {
+ Symbol *Sym = I.second;
+ auto *Undef = dyn_cast<Undefined>(Sym);
+ if (!Undef)
+ continue;
+ if (!Sym->IsUsedInRegularObj)
+ continue;
+
+ StringRef Name = Undef->getName();
+
+ if (Name.startswith("__imp_"))
+ continue;
+ // If we have an undefined symbol, but we have a Lazy representing a
+ // symbol we could load from file, make sure to load that.
+ Lazy *L = dyn_cast_or_null<Lazy>(find(("__imp_" + Name).str()));
+ if (!L || L->PendingArchiveLoad)
+ continue;
+
+ log("Loading lazy " + L->getName() + " from " + L->File->getName() +
+ " for automatic import");
+ L->PendingArchiveLoad = true;
+ L->File->addMember(&L->Sym);
+ }
+}
+
+bool SymbolTable::handleMinGWAutomaticImport(Symbol *Sym, StringRef Name) {
+ if (Name.startswith("__imp_"))
+ return false;
+ Defined *Imp = dyn_cast_or_null<Defined>(find(("__imp_" + Name).str()));
+ if (!Imp)
+ return false;
+
+ // Replace the reference directly to a variable with a reference
+ // to the import address table instead. This obviously isn't right,
+ // but we mark the symbol as IsRuntimePseudoReloc, and a later pass
+ // will add runtime pseudo relocations for every relocation against
+ // this Symbol. The runtime pseudo relocation framework expects the
+ // reference itself to point at the IAT entry.
+ size_t ImpSize = 0;
+ if (isa<DefinedImportData>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ cast<DefinedImportData>(Imp)->getDLLName());
+ ImpSize = sizeof(DefinedImportData);
+ } else if (isa<DefinedRegular>(Imp)) {
+ log("Automatically importing " + Name + " from " +
+ toString(cast<DefinedRegular>(Imp)->File));
+ ImpSize = sizeof(DefinedRegular);
+ } else {
+ warn("unable to automatically import " + Name + " from " + Imp->getName() +
+ " from " + toString(cast<DefinedRegular>(Imp)->File) +
+ "; unexpected symbol type");
+ return false;
+ }
+ Sym->replaceKeepingName(Imp, ImpSize);
+ Sym->IsRuntimePseudoReloc = true;
+
+ // There may exist symbols named .refptr.<name> which only consist
+ // of a single pointer to <name>. If it turns out <name> is
+ // automatically imported, we don't need to keep the .refptr.<name>
+ // pointer at all, but redirect all accesses to it to the IAT entry
+ // for __imp_<name> instead, and drop the whole .refptr.<name> chunk.
+ DefinedRegular *Refptr =
+ dyn_cast_or_null<DefinedRegular>(find((".refptr." + Name).str()));
+ if (Refptr && Refptr->getChunk()->getSize() == Config->Wordsize) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Refptr->getChunk());
+ if (SC && SC->Relocs.size() == 1 && *SC->symbols().begin() == Sym) {
+ log("Replacing .refptr." + Name + " with " + Imp->getName());
+ Refptr->getChunk()->Live = false;
+ Refptr->replaceKeepingName(Imp, ImpSize);
+ }
+ }
+ return true;
+}
+
void SymbolTable::reportRemainingUndefines() {
SmallPtrSet<Symbol *, 8> Undefs;
DenseMap<Symbol *, Symbol *> LocalImports;
@@ -169,9 +241,17 @@ void SymbolTable::reportRemainingUndefines() {
}
}
+ // We don't want to report missing Microsoft precompiled headers symbols.
+ // A proper message will be emitted instead in PDBLinker::aquirePrecompObj
+ if (Name.contains("_PchSym_"))
+ continue;
+
+ if (Config->MinGW && handleMinGWAutomaticImport(Sym, Name))
+ continue;
+
// Remaining undefined symbols are not fatal if /force is specified.
// They are replaced with dummy defined symbols.
- if (Config->Force)
+ if (Config->ForceUnresolved)
replaceSymbol<DefinedAbsolute>(Sym, Name, 0);
Undefs.insert(Sym);
}
@@ -181,10 +261,10 @@ void SymbolTable::reportRemainingUndefines() {
for (Symbol *B : Config->GCRoot) {
if (Undefs.count(B))
- errorOrWarn("<root>: undefined symbol: " + B->getName());
+ errorOrWarn("<root>: undefined symbol: " + toString(*B));
if (Config->WarnLocallyDefinedImported)
if (Symbol *Imp = LocalImports.lookup(B))
- warn("<root>: locally defined symbol imported: " + Imp->getName() +
+ warn("<root>: locally defined symbol imported: " + toString(*Imp) +
" (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
@@ -195,34 +275,41 @@ void SymbolTable::reportRemainingUndefines() {
if (!Sym)
continue;
if (Undefs.count(Sym))
- errorOrWarn("undefined symbol: " + Sym->getName() +
+ errorOrWarn("undefined symbol: " + toString(*Sym) +
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]");
+ warn(toString(File) +
+ ": locally defined symbol imported: " + toString(*Imp) +
+ " (defined in " + toString(Imp->getFile()) + ") [LNK4217]");
}
}
}
std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+ bool Inserted = false;
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
- if (Sym)
- return {Sym, false};
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- Sym->PendingArchiveLoad = false;
- return {Sym, true};
+ if (!Sym) {
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
+ Sym->PendingArchiveLoad = false;
+ Inserted = true;
+ }
+ return {Sym, Inserted};
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
+ std::pair<Symbol *, bool> Result = insert(Name);
+ if (!File || !isa<BitcodeFile>(File))
+ Result.first->IsUsedInRegularObj = true;
+ return Result;
}
Symbol *SymbolTable::addUndefined(StringRef Name, InputFile *F,
bool IsWeakAlias) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- if (!F || !isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, F);
if (WasInserted || (isa<Lazy>(S) && IsWeakAlias)) {
replaceSymbol<Undefined>(S, Name);
return S;
@@ -253,14 +340,20 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- error("duplicate symbol: " + toString(*Existing) + " in " +
- toString(Existing->getFile()) + " and in " + toString(NewFile));
+ std::string Msg = "duplicate symbol: " + toString(*Existing) + " in " +
+ toString(Existing->getFile()) + " and in " +
+ toString(NewFile);
+
+ if (Config->ForceMultiple)
+ warn(Msg);
+ else
+ error(Msg);
}
Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, Sym);
@@ -272,7 +365,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, COFFSymbolRef Sym) {
Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedAbsolute>(S, N, VA);
@@ -284,7 +377,7 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) {
Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S))
replaceSymbol<DefinedSynthetic>(S, N, C);
@@ -298,9 +391,7 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N,
SectionChunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S))
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ false,
/*IsExternal*/ true, Sym, C);
@@ -314,9 +405,7 @@ SymbolTable::addComdat(InputFile *F, StringRef N,
const coff_symbol_generic *Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedRegular>(S)) {
replaceSymbol<DefinedRegular>(S, F, N, /*IsCOMDAT*/ true,
/*IsExternal*/ true, Sym, nullptr);
@@ -331,9 +420,7 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
const coff_symbol_generic *Sym, CommonChunk *C) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
- if (!isa<BitcodeFile>(F))
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N, F);
if (WasInserted || !isa<DefinedCOFF>(S))
replaceSymbol<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S))
@@ -345,7 +432,7 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size,
Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N);
+ std::tie(S, WasInserted) = insert(N, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportData>(S, N, F);
@@ -360,7 +447,7 @@ Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID,
uint16_t Machine) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insert(Name, nullptr);
S->IsUsedInRegularObj = true;
if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) {
replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine);
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
index 30cb1a5410c3..00e55dbb7a02 100644
--- a/COFF/SymbolTable.h
+++ b/COFF/SymbolTable.h
@@ -54,6 +54,9 @@ public:
// symbols.
void reportRemainingUndefines();
+ void loadMinGWAutomaticImports();
+ bool handleMinGWAutomaticImport(Symbol *Sym, StringRef Name);
+
// Returns a list of chunks of selected symbols.
std::vector<Chunk *> getChunks();
@@ -108,7 +111,10 @@ public:
}
private:
+ /// Inserts symbol if not already present.
std::pair<Symbol *, bool> insert(StringRef Name);
+ /// Same as insert(Name), but also sets IsUsedInRegularObj.
+ std::pair<Symbol *, bool> insert(StringRef Name, InputFile *F);
StringRef findByPrefix(StringRef Prefix);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
@@ -117,6 +123,8 @@ private:
extern SymbolTable *Symtab;
+std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex);
+
} // namespace coff
} // namespace lld
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
index 7c8b7d5e8fc5..ccaf86417f10 100644
--- a/COFF/Symbols.cpp
+++ b/COFF/Symbols.cpp
@@ -54,7 +54,7 @@ InputFile *Symbol::getFile() {
bool Symbol::isLive() const {
if (auto *R = dyn_cast<DefinedRegular>(this))
- return R->getChunk()->isLive();
+ return R->getChunk()->Live;
if (auto *Imp = dyn_cast<DefinedImportData>(this))
return Imp->File->Live;
if (auto *Imp = dyn_cast<DefinedImportThunk>(this))
@@ -63,6 +63,13 @@ bool Symbol::isLive() const {
return true;
}
+// MinGW specific.
+void Symbol::replaceKeepingName(Symbol *Other, size_t Size) {
+ StringRef OrigName = Name;
+ memcpy(this, Other, Size);
+ Name = OrigName;
+}
+
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
size_t SymSize = cast<ObjFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
index 783965adbd9a..4a8693e22e3c 100644
--- a/COFF/Symbols.h
+++ b/COFF/Symbols.h
@@ -39,9 +39,9 @@ class Symbol {
public:
enum Kind {
// The order of these is significant. We start with the regular defined
- // symbols as those are the most prevelant and the zero tag is the cheapest
+ // symbols as those are the most prevalent and the zero tag is the cheapest
// to set. Among the defined kinds, the lower the kind is preferred over
- // the higher kind when testing wether one symbol should take precedence
+ // the higher kind when testing whether one symbol should take precedence
// over another.
DefinedRegularKind = 0,
DefinedCommonKind,
@@ -66,6 +66,8 @@ public:
// Returns the symbol name.
StringRef getName();
+ void replaceKeepingName(Symbol *Other, size_t Size);
+
// Returns the file from which this symbol was created.
InputFile *getFile();
@@ -78,7 +80,7 @@ protected:
explicit Symbol(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
WrittenToSymtab(false), PendingArchiveLoad(false), IsGCRoot(false),
- Name(N) {}
+ IsRuntimePseudoReloc(false), Name(N) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
@@ -102,6 +104,8 @@ public:
/// True if we've already added this symbol to the list of GC roots.
unsigned IsGCRoot : 1;
+ unsigned IsRuntimePseudoReloc : 1;
+
protected:
StringRef Name;
};
@@ -331,8 +335,8 @@ private:
Chunk *Data;
};
-// If you have a symbol "__imp_foo" in your object file, a symbol name
-// "foo" becomes automatically available as a pointer to "__imp_foo".
+// If you have a symbol "foo" in your object file, a symbol name
+// "__imp_foo" becomes automatically available as a pointer to "foo".
// This class is for such automatically-created symbols.
// Yes, this is an odd feature. We didn't intend to implement that.
// This is here just for compatibility with MSVC.
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index d17405ec26ab..258796ea6057 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -77,36 +77,38 @@ static const int SectorSize = 512;
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;
+static const int NumberOfDataDirectory = 16;
namespace {
class DebugDirectoryChunk : public Chunk {
public:
- DebugDirectoryChunk(const std::vector<Chunk *> &R) : Records(R) {}
+ DebugDirectoryChunk(const std::vector<Chunk *> &R, bool WriteRepro)
+ : Records(R), WriteRepro(WriteRepro) {}
size_t getSize() const override {
- return Records.size() * sizeof(debug_directory);
+ return (Records.size() + int(WriteRepro)) * sizeof(debug_directory);
}
void writeTo(uint8_t *B) const override {
auto *D = reinterpret_cast<debug_directory *>(B + OutputSectionOff);
for (const Chunk *Record : Records) {
- D->Characteristics = 0;
- D->TimeDateStamp = 0;
- D->MajorVersion = 0;
- D->MinorVersion = 0;
- D->Type = COFF::IMAGE_DEBUG_TYPE_CODEVIEW;
- D->SizeOfData = Record->getSize();
- D->AddressOfRawData = Record->getRVA();
OutputSection *OS = Record->getOutputSection();
uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA());
- D->PointerToRawData = Offs;
-
- TimeDateStamps.push_back(&D->TimeDateStamp);
+ fillEntry(D, COFF::IMAGE_DEBUG_TYPE_CODEVIEW, Record->getSize(),
+ Record->getRVA(), Offs);
++D;
}
+
+ if (WriteRepro) {
+ // FIXME: The COFF spec allows either a 0-sized entry to just say
+ // "the timestamp field is really a hash", or a 4-byte size field
+ // followed by that many bytes containing a longer hash (with the
+ // lowest 4 bytes usually being the timestamp in little-endian order).
+ // Consider storing the full 8 bytes computed by xxHash64 here.
+ fillEntry(D, COFF::IMAGE_DEBUG_TYPE_REPRO, 0, 0, 0);
+ }
}
void setTimeDateStamp(uint32_t TimeDateStamp) {
@@ -115,8 +117,23 @@ public:
}
private:
+ void fillEntry(debug_directory *D, COFF::DebugType DebugType, size_t Size,
+ uint64_t RVA, uint64_t Offs) const {
+ D->Characteristics = 0;
+ D->TimeDateStamp = 0;
+ D->MajorVersion = 0;
+ D->MinorVersion = 0;
+ D->Type = DebugType;
+ D->SizeOfData = Size;
+ D->AddressOfRawData = RVA;
+ D->PointerToRawData = Offs;
+
+ TimeDateStamps.push_back(&D->TimeDateStamp);
+ }
+
mutable std::vector<support::ulittle32_t *> TimeDateStamps;
const std::vector<Chunk *> &Records;
+ bool WriteRepro;
};
class CVDebugRecordChunk : public Chunk {
@@ -150,14 +167,22 @@ private:
void createSections();
void createMiscChunks();
void createImportTables();
+ void appendImportThunks();
+ void locateImportTables(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map);
void createExportTable();
void mergeSections();
+ void readRelocTargets();
+ void removeUnusedSections();
void assignAddresses();
+ void finalizeAddresses();
void removeEmptySections();
void createSymbolAndStringTable();
void openFile(StringRef OutputPath);
template <typename PEHeaderTy> void writeHeader();
void createSEHTable();
+ void createRuntimePseudoRelocs();
+ void insertCtorDtorSymbols();
void createGuardCFTables();
void markSymbolsForRVATable(ObjFile *File,
ArrayRef<SectionChunk *> SymIdxChunks,
@@ -168,6 +193,7 @@ private:
void writeSections();
void writeBuildId();
void sortExceptionTable();
+ void sortCRTSectionChunks(std::vector<Chunk *> &Chunks);
llvm::Optional<coff_symbol16> createSymbol(Defined *D);
size_t addEntryToStringTable(StringRef Str);
@@ -184,6 +210,10 @@ private:
std::vector<char> Strtab;
std::vector<llvm::object::coff_symbol16> OutputSymtab;
IdataContents Idata;
+ Chunk *ImportTableStart = nullptr;
+ uint64_t ImportTableSize = 0;
+ Chunk *IATStart = nullptr;
+ uint64_t IATSize = 0;
DelayLoadContents DelayIdata;
EdataContents Edata;
bool SetNoSEHCharacteristic = false;
@@ -191,7 +221,6 @@ private:
DebugDirectoryChunk *DebugDirectory = nullptr;
std::vector<Chunk *> DebugRecords;
CVDebugRecordChunk *BuildId = nullptr;
- Optional<codeview::DebugInfo> PreviousBuildId;
ArrayRef<uint8_t> SectionTable;
uint64_t FileSize;
@@ -209,6 +238,8 @@ private:
OutputSection *DidatSec;
OutputSection *RsrcSec;
OutputSection *RelocSec;
+ OutputSection *CtorsSec;
+ OutputSection *DtorsSec;
// The first and last .pdata sections in the output file.
//
@@ -237,6 +268,11 @@ void OutputSection::addChunk(Chunk *C) {
C->setOutputSection(this);
}
+void OutputSection::insertChunkAtStart(Chunk *C) {
+ Chunks.insert(Chunks.begin(), C);
+ C->setOutputSection(this);
+}
+
void OutputSection::setPermissions(uint32_t C) {
Header.Characteristics &= ~PermMask;
Header.Characteristics |= C;
@@ -267,77 +303,206 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) {
} // namespace coff
} // namespace lld
-// PDBs are matched against executables using a build id which consists of three
-// components:
-// 1. A 16-bit GUID
-// 2. An age
-// 3. A time stamp.
+// Check whether the target address S is in range from a relocation
+// of type RelType at address P.
+static bool isInRange(uint16_t RelType, uint64_t S, uint64_t P, int Margin) {
+ assert(Config->Machine == ARMNT);
+ int64_t Diff = AbsoluteDifference(S, P + 4) + Margin;
+ switch (RelType) {
+ case IMAGE_REL_ARM_BRANCH20T:
+ return isInt<21>(Diff);
+ case IMAGE_REL_ARM_BRANCH24T:
+ case IMAGE_REL_ARM_BLX23T:
+ return isInt<25>(Diff);
+ default:
+ return true;
+ }
+}
+
+// Return the last thunk for the given target if it is in range,
+// or create a new one.
+static std::pair<Defined *, bool>
+getThunk(DenseMap<uint64_t, Defined *> &LastThunks, Defined *Target, uint64_t P,
+ uint16_t Type, int Margin) {
+ Defined *&LastThunk = LastThunks[Target->getRVA()];
+ if (LastThunk && isInRange(Type, LastThunk->getRVA(), P, Margin))
+ return {LastThunk, false};
+ RangeExtensionThunk *C = make<RangeExtensionThunk>(Target);
+ Defined *D = make<DefinedSynthetic>("", C);
+ LastThunk = D;
+ return {D, true};
+}
+
+// This checks all relocations, and for any relocation which isn't in range
+// it adds a thunk after the section chunk that contains the relocation.
+// If the latest thunk for the specific target is in range, that is used
+// instead of creating a new thunk. All range checks are done with the
+// specified margin, to make sure that relocations that originally are in
+// range, but only barely, also get thunks - in case other added thunks makes
+// the target go out of range.
//
-// Debuggers and symbol servers match executables against debug info by checking
-// each of these components of the EXE/DLL against the corresponding value in
-// the PDB and failing a match if any of the components differ. In the case of
-// symbol servers, symbols are cached in a folder that is a function of the
-// GUID. As a result, in order to avoid symbol cache pollution where every
-// incremental build copies a new PDB to the symbol cache, we must try to re-use
-// the existing GUID if one exists, but bump the age. This way the match will
-// fail, so the symbol cache knows to use the new PDB, but the GUID matches, so
-// it overwrites the existing item in the symbol cache rather than making a new
-// one.
-static Optional<codeview::DebugInfo> loadExistingBuildId(StringRef Path) {
- // We don't need to incrementally update a previous build id if we're not
- // writing codeview debug info.
- if (!Config->Debug)
- return None;
+// After adding thunks, we verify that all relocations are in range (with
+// no extra margin requirements). If this failed, we restart (throwing away
+// the previously created thunks) and retry with a wider margin.
+static bool createThunks(std::vector<Chunk *> &Chunks, int Margin) {
+ bool AddressesChanged = false;
+ DenseMap<uint64_t, Defined *> LastThunks;
+ size_t ThunksSize = 0;
+ // Recheck Chunks.size() each iteration, since we can insert more
+ // elements into it.
+ for (size_t I = 0; I != Chunks.size(); ++I) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(Chunks[I]);
+ if (!SC)
+ continue;
+ size_t ThunkInsertionSpot = I + 1;
+
+ // Try to get a good enough estimate of where new thunks will be placed.
+ // Offset this by the size of the new thunks added so far, to make the
+ // estimate slightly better.
+ size_t ThunkInsertionRVA = SC->getRVA() + SC->getSize() + ThunksSize;
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *&RelocTarget = SC->RelocTargets[J];
+
+ // The estimate of the source address P should be pretty accurate,
+ // but we don't know whether the target Symbol address should be
+ // offset by ThunkSize or not (or by some of ThunksSize but not all of
+ // it), giving us some uncertainty once we have added one thunk.
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress + ThunksSize;
+
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
- auto ExpectedBinary = llvm::object::createBinary(Path);
- if (!ExpectedBinary) {
- consumeError(ExpectedBinary.takeError());
- return None;
+ uint64_t S = Sym->getRVA();
+
+ if (isInRange(Rel.Type, S, P, Margin))
+ continue;
+
+ // If the target isn't in range, hook it up to an existing or new
+ // thunk.
+ Defined *Thunk;
+ bool WasNew;
+ std::tie(Thunk, WasNew) = getThunk(LastThunks, Sym, P, Rel.Type, Margin);
+ if (WasNew) {
+ Chunk *ThunkChunk = Thunk->getChunk();
+ ThunkChunk->setRVA(
+ ThunkInsertionRVA); // Estimate of where it will be located.
+ Chunks.insert(Chunks.begin() + ThunkInsertionSpot, ThunkChunk);
+ ThunkInsertionSpot++;
+ ThunksSize += ThunkChunk->getSize();
+ ThunkInsertionRVA += ThunkChunk->getSize();
+ AddressesChanged = true;
+ }
+ RelocTarget = Thunk;
+ }
}
+ return AddressesChanged;
+}
- auto Binary = std::move(*ExpectedBinary);
- if (!Binary.getBinary()->isCOFF())
- return None;
+// Verify that all relocations are in range, with no extra margin requirements.
+static bool verifyRanges(const std::vector<Chunk *> Chunks) {
+ for (Chunk *C : Chunks) {
+ SectionChunk *SC = dyn_cast_or_null<SectionChunk>(C);
+ if (!SC)
+ continue;
- std::error_code EC;
- COFFObjectFile File(Binary.getBinary()->getMemoryBufferRef(), EC);
- if (EC)
- return None;
+ for (size_t J = 0, E = SC->Relocs.size(); J < E; ++J) {
+ const coff_relocation &Rel = SC->Relocs[J];
+ Symbol *RelocTarget = SC->RelocTargets[J];
- // If the machine of the binary we're outputting doesn't match the machine
- // of the existing binary, don't try to re-use the build id.
- if (File.is64() != Config->is64() || File.getMachine() != Config->Machine)
- return None;
+ Defined *Sym = dyn_cast_or_null<Defined>(RelocTarget);
+ if (!Sym)
+ continue;
- for (const auto &DebugDir : File.debug_directories()) {
- if (DebugDir.Type != IMAGE_DEBUG_TYPE_CODEVIEW)
- continue;
+ uint64_t P = SC->getRVA() + Rel.VirtualAddress;
+ uint64_t S = Sym->getRVA();
- const codeview::DebugInfo *ExistingDI = nullptr;
- StringRef PDBFileName;
- if (auto EC = File.getDebugPDBInfo(ExistingDI, PDBFileName)) {
- (void)EC;
- return None;
+ if (!isInRange(Rel.Type, S, P, 0))
+ return false;
}
- // We only support writing PDBs in v70 format. So if this is not a build
- // id that we recognize / support, ignore it.
- if (ExistingDI->Signature.CVSignature != OMF::Signature::PDB70)
- return None;
- return *ExistingDI;
}
- return None;
+ return true;
+}
+
+// Assign addresses and add thunks if necessary.
+void Writer::finalizeAddresses() {
+ assignAddresses();
+ if (Config->Machine != ARMNT)
+ return;
+
+ size_t OrigNumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ Sec->OrigChunks = Sec->Chunks;
+ OrigNumChunks += Sec->Chunks.size();
+ }
+
+ int Pass = 0;
+ int Margin = 1024 * 100;
+ while (true) {
+ // First check whether we need thunks at all, or if the previous pass of
+ // adding them turned out ok.
+ bool RangesOk = true;
+ size_t NumChunks = 0;
+ for (OutputSection *Sec : OutputSections) {
+ if (!verifyRanges(Sec->Chunks)) {
+ RangesOk = false;
+ break;
+ }
+ NumChunks += Sec->Chunks.size();
+ }
+ if (RangesOk) {
+ if (Pass > 0)
+ log("Added " + Twine(NumChunks - OrigNumChunks) + " thunks with " +
+ "margin " + Twine(Margin) + " in " + Twine(Pass) + " passes");
+ return;
+ }
+
+ if (Pass >= 10)
+ fatal("adding thunks hasn't converged after " + Twine(Pass) + " passes");
+
+ if (Pass > 0) {
+ // If the previous pass didn't work out, reset everything back to the
+ // original conditions before retrying with a wider margin. This should
+ // ideally never happen under real circumstances.
+ for (OutputSection *Sec : OutputSections) {
+ Sec->Chunks = Sec->OrigChunks;
+ for (Chunk *C : Sec->Chunks)
+ C->resetRelocTargets();
+ }
+ Margin *= 2;
+ }
+
+ // Try adding thunks everywhere where it is needed, with a margin
+ // to avoid things going out of range due to the added thunks.
+ bool AddressesChanged = false;
+ for (OutputSection *Sec : OutputSections)
+ AddressesChanged |= createThunks(Sec->Chunks, Margin);
+ // If the verification above thought we needed thunks, we should have
+ // added some.
+ assert(AddressesChanged);
+
+ // Recalculate the layout for the whole image (and verify the ranges at
+ // the start of the next round).
+ assignAddresses();
+
+ Pass++;
+ }
}
// The main function of the writer.
void Writer::run() {
ScopedTimer T1(CodeLayoutTimer);
+ createImportTables();
createSections();
createMiscChunks();
- createImportTables();
+ appendImportThunks();
createExportTable();
mergeSections();
- assignAddresses();
+ readRelocTargets();
+ removeUnusedSections();
+ finalizeAddresses();
removeEmptySections();
setSectionPermissions();
createSymbolAndStringTable();
@@ -346,9 +511,6 @@ void Writer::run() {
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);
openFile(Config->OutputFile);
if (Config->is64()) {
writeHeader<pe32plus_header>();
@@ -357,14 +519,14 @@ void Writer::run() {
}
writeSections();
sortExceptionTable();
- writeBuildId();
T1.stop();
if (!Config->PDBPath.empty() && Config->Debug) {
assert(BuildId);
- createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId);
+ createPDB(Symtab, OutputSections, SectionTable, BuildId->BuildId);
}
+ writeBuildId();
writeMapFile(OutputSections);
@@ -396,6 +558,110 @@ static void sortBySectionOrder(std::vector<Chunk *> &Chunks) {
});
}
+// Sort concrete section chunks from GNU import libraries.
+//
+// GNU binutils doesn't use short import files, but instead produces import
+// libraries that consist of object files, with section chunks for the .idata$*
+// sections. These are linked just as regular static libraries. Each import
+// library consists of one header object, one object file for every imported
+// symbol, and one trailer object. In order for the .idata tables/lists to
+// be formed correctly, the section chunks within each .idata$* section need
+// to be grouped by library, and sorted alphabetically within each library
+// (which makes sure the header comes first and the trailer last).
+static bool fixGnuImportChunks(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+
+ // Make sure all .idata$* section chunks are mapped as RDATA in order to
+ // be sorted into the same sections as our own synthesized .idata chunks.
+ for (auto &Pair : Map) {
+ StringRef SectionName = Pair.first.first;
+ uint32_t OutChars = Pair.first.second;
+ if (!SectionName.startswith(".idata"))
+ continue;
+ if (OutChars == RDATA)
+ continue;
+ std::vector<Chunk *> &SrcVect = Pair.second;
+ std::vector<Chunk *> &DestVect = Map[{SectionName, RDATA}];
+ DestVect.insert(DestVect.end(), SrcVect.begin(), SrcVect.end());
+ SrcVect.clear();
+ }
+
+ bool HasIdata = false;
+ // Sort all .idata$* chunks, grouping chunks from the same library,
+ // with alphabetical ordering of the object fils within a library.
+ for (auto &Pair : Map) {
+ StringRef SectionName = Pair.first.first;
+ if (!SectionName.startswith(".idata"))
+ continue;
+
+ std::vector<Chunk *> &Chunks = Pair.second;
+ if (!Chunks.empty())
+ HasIdata = true;
+ std::stable_sort(Chunks.begin(), Chunks.end(), [&](Chunk *S, Chunk *T) {
+ SectionChunk *SC1 = dyn_cast_or_null<SectionChunk>(S);
+ SectionChunk *SC2 = dyn_cast_or_null<SectionChunk>(T);
+ if (!SC1 || !SC2) {
+ // if SC1, order them ascending. If SC2 or both null,
+ // S is not less than T.
+ return SC1 != nullptr;
+ }
+ // Make a string with "libraryname/objectfile" for sorting, achieving
+ // both grouping by library and sorting of objects within a library,
+ // at once.
+ std::string Key1 =
+ (SC1->File->ParentName + "/" + SC1->File->getName()).str();
+ std::string Key2 =
+ (SC2->File->ParentName + "/" + SC2->File->getName()).str();
+ return Key1 < Key2;
+ });
+ }
+ return HasIdata;
+}
+
+// Add generated idata chunks, for imported symbols and DLLs, and a
+// terminator in .idata$2.
+static void addSyntheticIdata(
+ IdataContents &Idata,
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ Idata.create();
+
+ // Add the .idata content in the right section groups, to allow
+ // chunks from other linked in object files to be grouped together.
+ // See Microsoft PE/COFF spec 5.4 for details.
+ auto Add = [&](StringRef N, std::vector<Chunk *> &V) {
+ std::vector<Chunk *> &DestVect = Map[{N, RDATA}];
+ DestVect.insert(DestVect.end(), V.begin(), V.end());
+ };
+
+ // The loader assumes a specific order of data.
+ // Add each type in the correct order.
+ Add(".idata$2", Idata.Dirs);
+ Add(".idata$4", Idata.Lookups);
+ Add(".idata$5", Idata.Addresses);
+ Add(".idata$6", Idata.Hints);
+ Add(".idata$7", Idata.DLLNames);
+}
+
+// Locate the first Chunk and size of the import directory list and the
+// IAT.
+void Writer::locateImportTables(
+ std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> &Map) {
+ uint32_t RDATA = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ;
+ std::vector<Chunk *> &ImportTables = Map[{".idata$2", RDATA}];
+ if (!ImportTables.empty())
+ ImportTableStart = ImportTables.front();
+ for (Chunk *C : ImportTables)
+ ImportTableSize += C->getSize();
+
+ std::vector<Chunk *> &IAT = Map[{".idata$5", RDATA}];
+ if (!IAT.empty())
+ IATStart = IAT.front();
+ for (Chunk *C : IAT)
+ IATSize += C->getSize();
+}
+
// Create output section objects and add them to OutputSections.
void Writer::createSections() {
// First, create the builtin sections.
@@ -429,12 +695,14 @@ void Writer::createSections() {
DidatSec = CreateSection(".didat", DATA | R);
RsrcSec = CreateSection(".rsrc", DATA | R);
RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R);
+ CtorsSec = CreateSection(".ctors", DATA | R | W);
+ DtorsSec = CreateSection(".dtors", DATA | R | W);
// 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()) {
+ if (SC && !SC->Live) {
if (Config->Verbose)
SC->printDiscardedMessage();
continue;
@@ -442,26 +710,43 @@ void Writer::createSections() {
Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C);
}
+ // Even in non MinGW cases, we might need to link against GNU import
+ // libraries.
+ bool HasIdata = fixGnuImportChunks(Map);
+ if (!Idata.empty())
+ HasIdata = true;
+
+ if (HasIdata)
+ addSyntheticIdata(Idata, Map);
+
// Process an /order option.
if (!Config->Order.empty())
for (auto &Pair : Map)
sortBySectionOrder(Pair.second);
+ if (HasIdata)
+ locateImportTables(Map);
+
// 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.
- for (auto Pair : Map) {
+ for (auto &Pair : Map) {
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")
+ if (Name == ".CRT") {
+ // 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.
OutChars = DATA | R;
+ log("Processing section " + Pair.first.first + " -> " + Name);
+
+ sortCRTSectionChunks(Pair.second);
+ }
+
OutputSection *Sec = CreateSection(Name, OutChars);
std::vector<Chunk *> &Chunks = Pair.second;
for (Chunk *C : Chunks)
@@ -499,20 +784,20 @@ void Writer::createMiscChunks() {
}
// Create Debug Information Chunks
- if (Config->Debug) {
- DebugDirectory = make<DebugDirectoryChunk>(DebugRecords);
-
- OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
+ OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec;
+ if (Config->Debug || Config->Repro) {
+ DebugDirectory = make<DebugDirectoryChunk>(DebugRecords, Config->Repro);
+ DebugInfoSec->addChunk(DebugDirectory);
+ }
+ if (Config->Debug) {
// 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
// if we're ultimately not going to write CodeView data to the PDB.
- auto *CVChunk = make<CVDebugRecordChunk>();
- BuildId = CVChunk;
- DebugRecords.push_back(CVChunk);
+ BuildId = make<CVDebugRecordChunk>();
+ DebugRecords.push_back(BuildId);
- DebugInfoSec->addChunk(DebugDirectory);
for (Chunk *C : DebugRecords)
DebugInfoSec->addChunk(C);
}
@@ -524,6 +809,12 @@ void Writer::createMiscChunks() {
// Create /guard:cf tables if requested.
if (Config->GuardCF != GuardCFLevel::Off)
createGuardCFTables();
+
+ if (Config->MinGW) {
+ createRuntimePseudoRelocs();
+
+ insertCtorDtorSymbols();
+ }
}
// Create .idata section for the DLL-imported symbol table.
@@ -531,9 +822,6 @@ void Writer::createMiscChunks() {
// IdataContents class abstracted away the details for us,
// so we just let it create chunks and add them to the section.
void Writer::createImportTables() {
- if (ImportFile::Instances.empty())
- return;
-
// Initialize DLLOrder so that import entries are ordered in
// the same order as in the command line. (That affects DLL
// initialization order, and this ordering is MSVC-compatible.)
@@ -545,14 +833,6 @@ void Writer::createImportTables() {
if (Config->DLLOrder.count(DLL) == 0)
Config->DLLOrder[DLL] = Config->DLLOrder.size();
- 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);
@@ -565,10 +845,25 @@ void Writer::createImportTables() {
Idata.add(ImpSym);
}
}
+}
- if (!Idata.empty())
- for (Chunk *C : Idata.getChunks())
- IdataSec->addChunk(C);
+void Writer::appendImportThunks() {
+ if (ImportFile::Instances.empty())
+ return;
+
+ for (ImportFile *File : ImportFile::Instances) {
+ if (!File->Live)
+ continue;
+
+ if (!File->ThunkSym)
+ continue;
+
+ 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 (!DelayIdata.empty()) {
Defined *Helper = cast<Defined>(Config->DelayLoadHelper);
@@ -589,6 +884,21 @@ void Writer::createExportTable() {
EdataSec->addChunk(C);
}
+void Writer::removeUnusedSections() {
+ // Remove sections that we can be sure won't get content, to avoid
+ // allocating space for their section headers.
+ auto IsUnused = [this](OutputSection *S) {
+ if (S == RelocSec)
+ return false; // This section is populated later.
+ // MergeChunks have zero size at this point, as their size is finalized
+ // later. Only remove sections that have no Chunks at all.
+ return S->Chunks.empty();
+ };
+ OutputSections.erase(
+ std::remove_if(OutputSections.begin(), OutputSections.end(), IsUnused),
+ OutputSections.end());
+}
+
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
@@ -699,9 +1009,9 @@ void Writer::createSymbolAndStringTable() {
}
void Writer::mergeSections() {
- if (!PdataSec->getChunks().empty()) {
- FirstPdata = PdataSec->getChunks().front();
- LastPdata = PdataSec->getChunks().back();
+ if (!PdataSec->Chunks.empty()) {
+ FirstPdata = PdataSec->Chunks.front();
+ LastPdata = PdataSec->Chunks.back();
}
for (auto &P : Config->Merge) {
@@ -729,11 +1039,18 @@ void Writer::mergeSections() {
}
}
+// Visits all sections to initialize their relocation targets.
+void Writer::readRelocTargets() {
+ for (OutputSection *Sec : OutputSections)
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
+ [&](Chunk *C) { C->readRelocTargets(); });
+}
+
// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
void Writer::assignAddresses() {
SizeOfHeaders = DOSStubSize + sizeof(PEMagic) + sizeof(coff_file_header) +
- sizeof(data_directory) * NumberfOfDataDirectory +
+ sizeof(data_directory) * NumberOfDataDirectory +
sizeof(coff_section) * OutputSections.size();
SizeOfHeaders +=
Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header);
@@ -746,7 +1063,7 @@ void Writer::assignAddresses() {
addBaserels();
uint64_t RawSize = 0, VirtualSize = 0;
Sec->Header.VirtualAddress = RVA;
- for (Chunk *C : Sec->getChunks()) {
+ for (Chunk *C : Sec->Chunks) {
VirtualSize = alignTo(VirtualSize, C->Alignment);
C->setRVA(RVA + VirtualSize);
C->OutputSectionOff = VirtualSize;
@@ -808,7 +1125,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
if (!Config->Relocatable)
COFF->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
COFF->SizeOfOptionalHeader =
- sizeof(PEHeaderTy) + sizeof(data_directory) * NumberfOfDataDirectory;
+ sizeof(PEHeaderTy) + sizeof(data_directory) * NumberOfDataDirectory;
// Write PE header
auto *PE = reinterpret_cast<PEHeaderTy *>(Buf);
@@ -866,7 +1183,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH;
if (Config->TerminalServerAware)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE;
- PE->NumberOfRvaAndSize = NumberfOfDataDirectory;
+ PE->NumberOfRvaAndSize = NumberOfDataDirectory;
if (TextSec->getVirtualSize()) {
PE->BaseOfCode = TextSec->getRVA();
PE->SizeOfCode = TextSec->getRawSize();
@@ -875,16 +1192,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
// Write data directory
auto *Dir = reinterpret_cast<data_directory *>(Buf);
- Buf += sizeof(*Dir) * NumberfOfDataDirectory;
+ Buf += sizeof(*Dir) * NumberOfDataDirectory;
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();
- Dir[IMPORT_TABLE].Size = Idata.getDirSize();
- Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA();
- Dir[IAT].Size = Idata.getIATSize();
+ if (ImportTableStart) {
+ Dir[IMPORT_TABLE].RelativeVirtualAddress = ImportTableStart->getRVA();
+ Dir[IMPORT_TABLE].Size = ImportTableSize;
+ }
+ if (IATStart) {
+ Dir[IAT].RelativeVirtualAddress = IATStart->getRVA();
+ Dir[IAT].Size = IATSize;
}
if (RsrcSec->getVirtualSize()) {
Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA();
@@ -907,7 +1226,7 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
: sizeof(object::coff_tls_directory32);
}
}
- if (Config->Debug) {
+ if (DebugDirectory) {
Dir[DEBUG_DIRECTORY].RelativeVirtualAddress = DebugDirectory->getRVA();
Dir[DEBUG_DIRECTORY].Size = DebugDirectory->getSize();
}
@@ -1002,6 +1321,25 @@ static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) {
RVASet.insert({C, Off});
}
+// Given a symbol, add it to the GFIDs table if it is a live, defined, function
+// symbol in an executable section.
+static void maybeAddAddressTakenFunction(SymbolRVASet &AddressTakenSyms,
+ Symbol *S) {
+ auto *D = dyn_cast_or_null<DefinedCOFF>(S);
+
+ // Ignore undefined symbols and references to non-functions (e.g. globals and
+ // labels).
+ if (!D ||
+ D->getCOFFSymbol().getComplexType() != COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ return;
+
+ // Mark the symbol as address taken if it's in an executable section.
+ Chunk *RefChunk = D->getChunk();
+ OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr;
+ if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ addSymbolToRVASet(AddressTakenSyms, D);
+}
+
// Visit all relocations from all section contributions of this object file and
// mark the relocation target as address-taken.
static void markSymbolsWithRelocations(ObjFile *File,
@@ -1010,21 +1348,17 @@ static void markSymbolsWithRelocations(ObjFile *File,
// 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())
+ if (!SC || !SC->Live)
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);
- }
+ for (const coff_relocation &Reloc : SC->Relocs) {
+ if (Config->Machine == I386 && Reloc.Type == COFF::IMAGE_REL_I386_REL32)
+ // Ignore relative relocations on x86. On x86_64 they can't be ignored
+ // since they're also used to compute absolute addresses.
+ continue;
+
+ Symbol *Ref = SC->File->getSymbol(Reloc.SymbolTableIndex);
+ maybeAddAddressTakenFunction(UsedSymbols, Ref);
}
}
}
@@ -1051,7 +1385,11 @@ void Writer::createGuardCFTables() {
// Mark the image entry as address-taken.
if (Config->Entry)
- addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry));
+ maybeAddAddressTakenFunction(AddressTakenSyms, Config->Entry);
+
+ // Mark exported symbols in executable sections as address-taken.
+ for (Export &E : Config->Exports)
+ maybeAddAddressTakenFunction(AddressTakenSyms, E.Sym);
// Ensure sections referenced in the gfid table are 16-byte aligned.
for (const ChunkAndOffset &C : AddressTakenSyms)
@@ -1087,7 +1425,7 @@ void Writer::markSymbolsForRVATable(ObjFile *File,
// 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())
+ if (!C->Live)
continue;
// Validate that the contents look like symbol table indices.
@@ -1134,6 +1472,56 @@ void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym,
cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4);
}
+// MinGW specific. Gather all relocations that are imported from a DLL even
+// though the code didn't expect it to, produce the table that the runtime
+// uses for fixing them up, and provide the synthetic symbols that the
+// runtime uses for finding the table.
+void Writer::createRuntimePseudoRelocs() {
+ std::vector<RuntimePseudoReloc> Rels;
+
+ for (Chunk *C : Symtab->getChunks()) {
+ auto *SC = dyn_cast<SectionChunk>(C);
+ if (!SC || !SC->Live)
+ continue;
+ SC->getRuntimePseudoRelocs(Rels);
+ }
+
+ if (!Rels.empty())
+ log("Writing " + Twine(Rels.size()) + " runtime pseudo relocations");
+ PseudoRelocTableChunk *Table = make<PseudoRelocTableChunk>(Rels);
+ RdataSec->addChunk(Table);
+ EmptyChunk *EndOfList = make<EmptyChunk>();
+ RdataSec->addChunk(EndOfList);
+
+ Symbol *HeadSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST__");
+ Symbol *EndSym = Symtab->findUnderscore("__RUNTIME_PSEUDO_RELOC_LIST_END__");
+ replaceSymbol<DefinedSynthetic>(HeadSym, HeadSym->getName(), Table);
+ replaceSymbol<DefinedSynthetic>(EndSym, EndSym->getName(), EndOfList);
+}
+
+// MinGW specific.
+// The MinGW .ctors and .dtors lists have sentinels at each end;
+// a (uintptr_t)-1 at the start and a (uintptr_t)0 at the end.
+// There's a symbol pointing to the start sentinel pointer, __CTOR_LIST__
+// and __DTOR_LIST__ respectively.
+void Writer::insertCtorDtorSymbols() {
+ AbsolutePointerChunk *CtorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *CtorListEnd = make<AbsolutePointerChunk>(0);
+ AbsolutePointerChunk *DtorListHead = make<AbsolutePointerChunk>(-1);
+ AbsolutePointerChunk *DtorListEnd = make<AbsolutePointerChunk>(0);
+ CtorsSec->insertChunkAtStart(CtorListHead);
+ CtorsSec->addChunk(CtorListEnd);
+ DtorsSec->insertChunkAtStart(DtorListHead);
+ DtorsSec->addChunk(DtorListEnd);
+
+ Symbol *CtorListSym = Symtab->findUnderscore("__CTOR_LIST__");
+ Symbol *DtorListSym = Symtab->findUnderscore("__DTOR_LIST__");
+ replaceSymbol<DefinedSynthetic>(CtorListSym, CtorListSym->getName(),
+ CtorListHead);
+ replaceSymbol<DefinedSynthetic>(DtorListSym, DtorListSym->getName(),
+ DtorListHead);
+}
+
// Handles /section options to allow users to overwrite
// section attributes.
void Writer::setSectionPermissions() {
@@ -1160,7 +1548,7 @@ void Writer::writeSections() {
// ADD instructions).
if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE)
memset(SecBuf, 0xCC, Sec->getRawSize());
- for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(),
+ for_each(parallel::par, Sec->Chunks.begin(), Sec->Chunks.end(),
[&](Chunk *C) { C->writeTo(SecBuf); });
}
}
@@ -1171,25 +1559,10 @@ void Writer::writeBuildId() {
// 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).
+ // PE contents.
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);
- }
+ // BuildId->BuildId was filled in when the PDB was written.
}
// At this point the only fields in the COFF file which remain unset are the
@@ -1201,8 +1574,25 @@ void Writer::writeBuildId() {
Buffer->getBufferSize());
uint32_t Timestamp = Config->Timestamp;
+ uint64_t Hash = 0;
+ bool GenerateSyntheticBuildId =
+ Config->MinGW && Config->Debug && Config->PDBPath.empty();
+
+ if (Config->Repro || GenerateSyntheticBuildId)
+ Hash = xxHash64(OutputFileData);
+
if (Config->Repro)
- Timestamp = static_cast<uint32_t>(xxHash64(OutputFileData));
+ Timestamp = static_cast<uint32_t>(Hash);
+
+ if (GenerateSyntheticBuildId) {
+ // For MinGW builds without a PDB file, we still generate a build id
+ // to allow associating a crash dump to the executable.
+ BuildId->BuildId->PDB70.CVSignature = OMF::Signature::PDB70;
+ BuildId->BuildId->PDB70.Age = 1;
+ memcpy(BuildId->BuildId->PDB70.Signature, &Hash, 8);
+ // xxhash only gives us 8 bytes, so put some fixed data in the other half.
+ memcpy(&BuildId->BuildId->PDB70.Signature[8], "LLD PDB.", 8);
+ }
if (DebugDirectory)
DebugDirectory->setTimeDateStamp(Timestamp);
@@ -1240,6 +1630,42 @@ void Writer::sortExceptionTable() {
errs() << "warning: don't know how to handle .pdata.\n";
}
+// The CRT section contains, among other things, the array of function
+// pointers that initialize every global variable that is not trivially
+// constructed. The CRT calls them one after the other prior to invoking
+// main().
+//
+// As per C++ spec, 3.6.2/2.3,
+// "Variables with ordered initialization defined within a single
+// translation unit shall be initialized in the order of their definitions
+// in the translation unit"
+//
+// It is therefore critical to sort the chunks containing the function
+// pointers in the order that they are listed in the object file (top to
+// bottom), otherwise global objects might not be initialized in the
+// correct order.
+void Writer::sortCRTSectionChunks(std::vector<Chunk *> &Chunks) {
+ auto SectionChunkOrder = [](const Chunk *A, const Chunk *B) {
+ auto SA = dyn_cast<SectionChunk>(A);
+ auto SB = dyn_cast<SectionChunk>(B);
+ assert(SA && SB && "Non-section chunks in CRT section!");
+
+ StringRef SAObj = SA->File->MB.getBufferIdentifier();
+ StringRef SBObj = SB->File->MB.getBufferIdentifier();
+
+ return SAObj == SBObj && SA->getSectionNumber() < SB->getSectionNumber();
+ };
+ std::stable_sort(Chunks.begin(), Chunks.end(), SectionChunkOrder);
+
+ if (Config->Verbose) {
+ for (auto &C : Chunks) {
+ auto SC = dyn_cast<SectionChunk>(C);
+ log(" " + SC->File->MB.getBufferIdentifier().str() +
+ ", SectionID: " + Twine(SC->getSectionNumber()));
+ }
+ }
+}
+
OutputSection *Writer::findSection(StringRef Name) {
for (OutputSection *Sec : OutputSections)
if (Sec->Name == Name)
@@ -1259,12 +1685,13 @@ uint32_t Writer::getSizeOfInitializedData() {
void Writer::addBaserels() {
if (!Config->Relocatable)
return;
+ RelocSec->Chunks.clear();
std::vector<Baserel> V;
for (OutputSection *Sec : OutputSections) {
if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
continue;
// Collect all locations for base relocations.
- for (Chunk *C : Sec->getChunks())
+ for (Chunk *C : Sec->Chunks)
C->getBaserels(&V);
// Add the addresses to .reloc section.
if (!V.empty())
diff --git a/COFF/Writer.h b/COFF/Writer.h
index d37276cb6d91..727582480c91 100644
--- a/COFF/Writer.h
+++ b/COFF/Writer.h
@@ -34,8 +34,8 @@ public:
Header.Characteristics = Chars;
}
void addChunk(Chunk *C);
+ void insertChunkAtStart(Chunk *C);
void merge(OutputSection *Other);
- ArrayRef<Chunk *> getChunks() { return Chunks; }
void addPermissions(uint32_t C);
void setPermissions(uint32_t C);
uint64_t getRVA() { return Header.VirtualAddress; }
@@ -62,9 +62,11 @@ public:
llvm::StringRef Name;
llvm::object::coff_section Header = {};
+ std::vector<Chunk *> Chunks;
+ std::vector<Chunk *> OrigChunks;
+
private:
uint32_t StringTableOff = 0;
- std::vector<Chunk *> Chunks;
};
}
diff --git a/Common/Args.cpp b/Common/Args.cpp
index ff77bfcc3b76..3f0671d72a66 100644
--- a/Common/Args.cpp
+++ b/Common/Args.cpp
@@ -13,6 +13,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/ArgList.h"
+#include "llvm/Support/Path.h"
using namespace llvm;
using namespace lld;
@@ -40,7 +41,7 @@ std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) {
uint64_t lld::args::getZOptionValue(opt::InputArgList &Args, int Id,
StringRef Key, uint64_t Default) {
- for (auto *Arg : Args.filtered(Id)) {
+ for (auto *Arg : Args.filtered_reverse(Id)) {
std::pair<StringRef, StringRef> KV = StringRef(Arg->getValue()).split('=');
if (KV.first == Key) {
uint64_t Result = Default;
@@ -64,3 +65,9 @@ std::vector<StringRef> lld::args::getLines(MemoryBufferRef MB) {
}
return Ret;
}
+
+StringRef lld::args::getFilenameWithoutExe(StringRef Path) {
+ if (Path.endswith_lower(".exe"))
+ return sys::path::stem(Path);
+ return sys::path::filename(Path);
+}
diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp
index d1cb3dbbe03c..c059516daf94 100644
--- a/Common/ErrorHandler.cpp
+++ b/Common/ErrorHandler.cpp
@@ -47,8 +47,9 @@ ErrorHandler &lld::errorHandler() {
}
void lld::exitLld(int Val) {
- // Delete the output buffer so that any tempory file is deleted.
- errorHandler().OutputBuffer.reset();
+ // Delete any temporary file, while keeping the memory mapping open.
+ if (errorHandler().OutputBuffer)
+ errorHandler().OutputBuffer->discard();
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
diff --git a/Common/Strings.cpp b/Common/Strings.cpp
index 36f4f77d8476..6f74865b7f42 100644
--- a/Common/Strings.cpp
+++ b/Common/Strings.cpp
@@ -16,14 +16,6 @@
#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;
@@ -45,18 +37,21 @@ Optional<std::string> lld::demangleItanium(StringRef Name) {
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);
+Optional<std::string> lld::demangleMSVC(StringRef Name) {
+ std::string Prefix;
+ if (Name.consume_front("__imp_"))
+ Prefix = "__declspec(dllimport) ";
+
+ // Demangle only C++ names.
+ if (!Name.startswith("?"))
+ return None;
- 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;
+ char *Buf = microsoftDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+ if (!Buf)
+ return None;
+ std::string S(Buf);
+ free(Buf);
+ return Prefix + S;
}
StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) {
diff --git a/Common/TargetOptionsCommandFlags.cpp b/Common/TargetOptionsCommandFlags.cpp
index b46df363c361..7a3fc510704f 100644
--- a/Common/TargetOptionsCommandFlags.cpp
+++ b/Common/TargetOptionsCommandFlags.cpp
@@ -32,3 +32,4 @@ llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() {
}
std::string lld::GetCPUStr() { return ::getCPUStr(); }
+std::vector<std::string> lld::GetMAttrs() { return ::MAttrs; }
diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp
index 7551919cf86f..ac753cb58265 100644
--- a/ELF/AArch64ErrataFix.cpp
+++ b/ELF/AArch64ErrataFix.cpp
@@ -356,7 +356,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off,
}
uint64_t PatchOff = 0;
- const uint8_t *Buf = IS->Data.begin();
+ const uint8_t *Buf = IS->data().begin();
const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off);
uint32_t Instr1 = *InstBuf++;
uint32_t Instr2 = *InstBuf++;
@@ -411,7 +411,7 @@ uint64_t lld::elf::Patch843419Section::getLDSTAddr() const {
void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) {
// Copy the instruction that we will be replacing with a branch in the
// Patchee Section.
- write32le(Buf, read32le(Patchee->Data.begin() + PatcheeOffset));
+ write32le(Buf, read32le(Patchee->data().begin() + PatcheeOffset));
// Apply any relocation transferred from the original PatcheeSection.
// For a SyntheticSection Buf already has OutSecOff added, but relocateAlloc
@@ -451,7 +451,7 @@ void AArch64Err843419Patcher::init() {
continue;
if (!IsCodeMapSymbol(Def) && !IsDataMapSymbol(Def))
continue;
- if (auto *Sec = dyn_cast<InputSection>(Def->Section))
+ if (auto *Sec = dyn_cast_or_null<InputSection>(Def->Section))
if (Sec->Flags & SHF_EXECINSTR)
SectionMap[Sec].push_back(Def);
}
@@ -487,7 +487,8 @@ void AArch64Err843419Patcher::insertPatches(
InputSectionDescription &ISD, std::vector<Patch843419Section *> &Patches) {
uint64_t ISLimit;
uint64_t PrevISLimit = ISD.Sections.front()->OutSecOff;
- uint64_t PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ uint64_t PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
+ uint64_t OutSecAddr = ISD.Sections.front()->getParent()->Addr;
// Set the OutSecOff of patches to the place where we want to insert them.
// We use a similar strategy to Thunk placement. Place patches roughly
@@ -498,12 +499,12 @@ void AArch64Err843419Patcher::insertPatches(
ISLimit = IS->OutSecOff + IS->getSize();
if (ISLimit > PatchUpperBound) {
while (PatchIt != PatchEnd) {
- if ((*PatchIt)->getLDSTAddr() >= PrevISLimit)
+ if ((*PatchIt)->getLDSTAddr() - OutSecAddr >= PrevISLimit)
break;
(*PatchIt)->OutSecOff = PrevISLimit;
++PatchIt;
}
- PatchUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ PatchUpperBound = PrevISLimit + Target->getThunkSectionSpacing();
}
PrevISLimit = ISLimit;
}
@@ -538,20 +539,24 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset,
InputSection *IS,
std::vector<Patch843419Section *> &Patches) {
// There may be a relocation at the same offset that we are patching. There
- // are three cases that we need to consider.
+ // are four cases that we need to consider.
// Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this
// instance of the erratum on a previous patch and altered the relocation. We
// have nothing more to do.
- // Case 2: A load/store register (unsigned immediate) class relocation. There
+ // Case 2: A TLS Relaxation R_RELAX_TLS_IE_TO_LE. In this case the ADRP that
+ // we read will be transformed into a MOVZ later so we actually don't match
+ // the sequence and have nothing more to do.
+ // Case 3: A load/store register (unsigned immediate) class relocation. There
// are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and
// they are both absolute. We need to add the same relocation to the patch,
// and replace the relocation with a R_AARCH_JUMP26 branch relocation.
- // Case 3: No relocation. We must create a new R_AARCH64_JUMP26 branch
+ // Case 4: No relocation. We must create a new R_AARCH64_JUMP26 branch
// relocation at the offset.
auto RelIt = std::find_if(
IS->Relocations.begin(), IS->Relocations.end(),
[=](const Relocation &R) { return R.Offset == PatcheeOffset; });
- if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26)
+ if (RelIt != IS->Relocations.end() &&
+ (RelIt->Type == R_AARCH64_JUMP26 || RelIt->Expr == R_RELAX_TLS_IE_TO_LE))
return;
log("detected cortex-a53-843419 erratum sequence starting at " +
@@ -598,7 +603,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
auto DataSym = std::next(CodeSym);
uint64_t Off = (*CodeSym)->Value;
uint64_t Limit =
- (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value;
+ (DataSym == MapSyms.end()) ? IS->data().size() : (*DataSym)->Value;
while (Off < Limit) {
uint64_t StartAddr = IS->getVA(Off);
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index c7b3c0801de2..08ffe2a08c0f 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -41,6 +41,7 @@ public:
int32_t Index, unsigned RelOff) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
bool usesOnlyLowPageBits(RelType Type) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
@@ -57,6 +58,7 @@ AArch64::AArch64() {
RelativeRel = R_AARCH64_RELATIVE;
IRelativeRel = R_AARCH64_IRELATIVE;
GotRel = R_AARCH64_GLOB_DAT;
+ NoneRel = R_AARCH64_NONE;
PltRel = R_AARCH64_JUMP_SLOT;
TlsDescRel = R_AARCH64_TLSDESC;
TlsGotRel = R_AARCH64_TLS_TPREL64;
@@ -66,22 +68,18 @@ AArch64::AArch64() {
PltHeaderSize = 32;
DefaultMaxPageSize = 65536;
- // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant
- // 1 of the tls structures and the tcb size is 16.
- TcbSize = 16;
- NeedsThunks = true;
+ // Align to the 2 MiB page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes 2 MiB-aligned allocations.
+ DefaultImageBase = 0x200000;
- // See comment in Arch/ARM.cpp for a more detailed explanation of
- // ThunkSectionSpacing. For AArch64 the only branches we are permitted to
- // Thunk have a range of +/- 128 MiB
- ThunkSectionSpacing = (128 * 1024 * 1024) - 0x30000;
+ NeedsThunks = true;
}
RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
case R_AARCH64_TLSDESC_ADR_PAGE21:
- return R_TLSDESC_PAGE;
+ return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
case R_AARCH64_TLSDESC_ADD_LO12:
return R_TLSDESC;
@@ -107,13 +105,13 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S,
case R_AARCH64_LD_PREL_LO19:
return R_PC;
case R_AARCH64_ADR_PREL_PG_HI21:
- return R_PAGE_PC;
+ return R_AARCH64_PAGE_PC;
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return R_GOT;
case R_AARCH64_ADR_GOT_PAGE:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
- return R_GOT_PAGE_PC;
+ return R_AARCH64_GOT_PAGE_PC;
case R_AARCH64_NONE:
return R_NONE;
default:
@@ -125,7 +123,7 @@ RelExpr AArch64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const {
if (Expr == R_RELAX_TLS_GD_TO_IE) {
if (Type == R_AARCH64_TLSDESC_ADR_PAGE21)
- return R_RELAX_TLS_GD_TO_IE_PAGE_PC;
+ return R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
return R_RELAX_TLS_GD_TO_IE_ABS;
}
return Expr;
@@ -156,7 +154,7 @@ RelType AArch64::getDynRel(RelType Type) const {
}
void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- write64le(Buf, InX::Plt->getVA());
+ write64le(Buf, In.Plt->getVA());
}
void AArch64::writePltHeader(uint8_t *Buf) const {
@@ -172,8 +170,8 @@ void AArch64::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t Got = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t Got = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(Got + 16) - getAArch64Page(Plt + 4));
relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16);
@@ -208,6 +206,13 @@ bool AArch64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return !inBranchRange(Type, BranchAddr, Dst);
}
+uint32_t AArch64::getThunkSectionSpacing() const {
+ // See comment in Arch/ARM.cpp for a more detailed explanation of
+ // getThunkSectionSpacing(). For AArch64 the only branches we are permitted to
+ // Thunk have a range of +/- 128 MiB
+ return (128 * 1024 * 1024) - 0x30000;
+}
+
bool AArch64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
if (Type != R_AARCH64_CALL26 && Type != R_AARCH64_JUMP26)
return true;
@@ -338,7 +343,7 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, (Val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
- checkInt(Loc, Val, 24, Type);
+ checkUInt(Loc, Val, 24, Type);
or32AArch64Imm(Loc, Val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp
index 48b27f23510c..a7c6c84ceecd 100644
--- a/ELF/Arch/AMDGPU.cpp
+++ b/ELF/Arch/AMDGPU.cpp
@@ -35,6 +35,7 @@ public:
AMDGPU::AMDGPU() {
RelativeRel = R_AMDGPU_RELATIVE64;
GotRel = R_AMDGPU_ABS64;
+ NoneRel = R_AMDGPU_NONE;
GotEntrySize = 8;
}
diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp
index acf9a615f20b..120caca671af 100644
--- a/ELF/Arch/ARM.cpp
+++ b/ELF/Arch/ARM.cpp
@@ -40,6 +40,7 @@ public:
void addPltHeaderSymbols(InputSection &ISD) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
};
@@ -50,6 +51,7 @@ ARM::ARM() {
RelativeRel = R_ARM_RELATIVE;
IRelativeRel = R_ARM_IRELATIVE;
GotRel = R_ARM_GLOB_DAT;
+ NoneRel = R_ARM_NONE;
PltRel = R_ARM_JUMP_SLOT;
TlsGotRel = R_ARM_TLS_TPOFF32;
TlsModuleIndexRel = R_ARM_TLS_DTPMOD32;
@@ -59,41 +61,8 @@ ARM::ARM() {
GotPltEntrySize = 4;
PltEntrySize = 16;
PltHeaderSize = 32;
- TrapInstr = 0xd4d4d4d4;
- // ARM uses Variant 1 TLS
- TcbSize = 8;
+ TrapInstr = {0xd4, 0xd4, 0xd4, 0xd4};
NeedsThunks = true;
-
- // The placing of pre-created ThunkSections is controlled by the
- // ThunkSectionSpacing parameter. The aim is to place the
- // ThunkSection such that all branches from the InputSections prior to the
- // ThunkSection can reach a Thunk placed at the end of the ThunkSection.
- // Graphically:
- // | up to ThunkSectionSpacing .text input sections |
- // | ThunkSection |
- // | up to ThunkSectionSpacing .text input sections |
- // | ThunkSection |
-
- // Pre-created ThunkSections are spaced roughly 16MiB apart on ARM. This is to
- // match the most common expected case of a Thumb 2 encoded BL, BLX or B.W
- // ARM B, BL, BLX range +/- 32MiB
- // Thumb B.W, BL, BLX range +/- 16MiB
- // Thumb B<cc>.W range +/- 1MiB
- // If a branch cannot reach a pre-created ThunkSection a new one will be
- // created so we can handle the rare cases of a Thumb 2 conditional branch.
- // We intentionally use a lower size for ThunkSectionSpacing than the maximum
- // branch range so the end of the ThunkSection is more likely to be within
- // range of the branch instruction that is furthest away. The value we shorten
- // ThunkSectionSpacing by is set conservatively to allow us to create 16,384
- // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to
- // one of the Thunks going out of range.
-
- // FIXME: lld assumes that the Thumb BL and BLX encoding permits the J1 and
- // J2 bits to be used to extend the branch range. On earlier Architectures
- // such as ARMv4, ARMv5 and ARMv6 (except ARMv6T2) the range is +/- 4MiB. If
- // support for the earlier encodings is added then when they are used the
- // ThunkSectionSpacing will need lowering.
- ThunkSectionSpacing = 0x1000000 - 0x30000;
}
uint32_t ARM::calcEFlags() const {
@@ -165,6 +134,12 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S,
return R_NONE;
case R_ARM_TLS_LE32:
return R_TLS;
+ case R_ARM_V4BX:
+ // V4BX is just a marker to indicate there's a "bx rN" instruction at the
+ // given address. It can be used to implement a special linker mode which
+ // rewrites ARMv4T inputs to ARMv4. Since we support only ARMv4 input and
+ // not ARMv4 output, we can just ignore it.
+ return R_HINT;
default:
return R_ABS;
}
@@ -177,7 +152,7 @@ RelType ARM::getDynRel(RelType Type) const {
}
void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- write32le(Buf, InX::Plt->getVA());
+ write32le(Buf, In.Plt->getVA());
}
void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const {
@@ -198,8 +173,8 @@ static void writePltHeaderLong(uint8_t *Buf) {
0xd4, 0xd4, 0xd4, 0xd4, // Pad to 32-byte boundary
0xd4, 0xd4, 0xd4, 0xd4};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t L1 = InX::Plt->getVA() + 8;
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t L1 = In.Plt->getVA() + 8;
write32le(Buf + 16, GotPlt - L1 - 8);
}
@@ -217,7 +192,7 @@ void ARM::writePltHeader(uint8_t *Buf) const {
0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4)
};
- uint64_t Offset = InX::GotPlt->getVA() - InX::Plt->getVA() - 4;
+ uint64_t Offset = In.GotPlt->getVA() - In.Plt->getVA() - 4;
if (!llvm::isUInt<27>(Offset)) {
// We cannot encode the Offset, use the long form.
writePltHeaderLong(Buf);
@@ -227,10 +202,10 @@ void ARM::writePltHeader(uint8_t *Buf) const {
write32le(Buf + 4, PltData[1] | ((Offset >> 20) & 0xff));
write32le(Buf + 8, PltData[2] | ((Offset >> 12) & 0xff));
write32le(Buf + 12, PltData[3] | (Offset & 0xfff));
- write32le(Buf + 16, TrapInstr); // Pad to 32-byte boundary
- write32le(Buf + 20, TrapInstr);
- write32le(Buf + 24, TrapInstr);
- write32le(Buf + 28, TrapInstr);
+ memcpy(Buf + 16, TrapInstr.data(), 4); // Pad to 32-byte boundary
+ memcpy(Buf + 20, TrapInstr.data(), 4);
+ memcpy(Buf + 24, TrapInstr.data(), 4);
+ memcpy(Buf + 28, TrapInstr.data(), 4);
}
void ARM::addPltHeaderSymbols(InputSection &IS) const {
@@ -279,7 +254,7 @@ void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
write32le(Buf + 0, PltData[0] | ((Offset >> 20) & 0xff));
write32le(Buf + 4, PltData[1] | ((Offset >> 12) & 0xff));
write32le(Buf + 8, PltData[2] | (Offset & 0xfff));
- write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary
+ memcpy(Buf + 12, TrapInstr.data(), 4); // Pad to 16-byte boundary
}
void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const {
@@ -324,6 +299,40 @@ bool ARM::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
+uint32_t ARM::getThunkSectionSpacing() const {
+ // The placing of pre-created ThunkSections is controlled by the value
+ // ThunkSectionSpacing returned by getThunkSectionSpacing(). The aim is to
+ // place the ThunkSection such that all branches from the InputSections
+ // prior to the ThunkSection can reach a Thunk placed at the end of the
+ // ThunkSection. Graphically:
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+ // | up to ThunkSectionSpacing .text input sections |
+ // | ThunkSection |
+
+ // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This
+ // is to match the most common expected case of a Thumb 2 encoded BL, BLX or
+ // B.W:
+ // ARM B, BL, BLX range +/- 32MiB
+ // Thumb B.W, BL, BLX range +/- 16MiB
+ // Thumb B<cc>.W range +/- 1MiB
+ // If a branch cannot reach a pre-created ThunkSection a new one will be
+ // created so we can handle the rare cases of a Thumb 2 conditional branch.
+ // We intentionally use a lower size for ThunkSectionSpacing than the maximum
+ // branch range so the end of the ThunkSection is more likely to be within
+ // range of the branch instruction that is furthest away. The value we shorten
+ // ThunkSectionSpacing by is set conservatively to allow us to create 16,384
+ // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to
+ // one of the Thunks going out of range.
+
+ // On Arm the ThunkSectionSpacing depends on the range of the Thumb Branch
+ // range. On earlier Architectures such as ARMv4, ARMv5 and ARMv6 (except
+ // ARMv6T2) the range is +/- 4MiB.
+
+ return (Config->ARMJ1J2BranchEncoding) ? 0x1000000 - 0x30000
+ : 0x400000 - 0x7500;
+}
+
bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
uint64_t Range;
uint64_t InstrSize;
@@ -342,7 +351,7 @@ bool ARM::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
break;
case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL:
- Range = 0x1000000;
+ Range = Config->ARMJ1J2BranchEncoding ? 0x1000000 : 0x400000;
InstrSize = 2;
break;
default:
@@ -447,11 +456,23 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
// Bit 12 is 0 for BLX, 1 for BL
write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12);
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ checkInt(Loc, Val, 23, Type);
+ write16le(Loc,
+ 0xf000 | // opcode
+ ((Val >> 12) & 0x07ff)); // imm11
+ write16le(Loc + 2,
+ (read16le(Loc + 2) & 0xd000) | // opcode
+ 0x2800 | // J1 == J2 == 1
+ ((Val >> 1) & 0x07ff)); // imm11
+ break;
+ }
// Fall through as rest of encoding is the same as B.W
LLVM_FALLTHROUGH;
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
- // FIXME: Use of I1 and I2 require v6T2ops
checkInt(Loc, Val, 25, Type);
write16le(Loc,
0xf000 | // opcode
@@ -470,14 +491,12 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
break;
case R_ARM_MOVT_ABS:
case R_ARM_MOVT_PREL:
- 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(Loc, Val, 32, Type);
write16le(Loc,
0xf2c0 | // opcode
((Val >> 17) & 0x0400) | // i
@@ -542,10 +561,19 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, RelType Type) const {
((Lo & 0x07ff) << 1)); // imm11:0
}
case R_ARM_THM_CALL:
+ if (!Config->ARMJ1J2BranchEncoding) {
+ // Older Arm architectures do not support R_ARM_THM_JUMP24 and have
+ // different encoding rules and range due to J1 and J2 always being 1.
+ uint16_t Hi = read16le(Buf);
+ uint16_t Lo = read16le(Buf + 2);
+ return SignExtend64<22>(((Hi & 0x7ff) << 12) | // imm11
+ ((Lo & 0x7ff) << 1)); // imm11:0
+ break;
+ }
+ LLVM_FALLTHROUGH;
case R_ARM_THM_JUMP24: {
// Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0
// I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S)
- // FIXME: I1 and I2 require v6T2ops
uint16_t Hi = read16le(Buf);
uint16_t Lo = read16le(Buf + 2);
return SignExtend64<24>(((Hi & 0x0400) << 14) | // S
diff --git a/ELF/Arch/AVR.cpp b/ELF/Arch/AVR.cpp
index 02ac770127b9..637da3778bd2 100644
--- a/ELF/Arch/AVR.cpp
+++ b/ELF/Arch/AVR.cpp
@@ -43,12 +43,15 @@ using namespace lld::elf;
namespace {
class AVR final : public TargetInfo {
public:
+ AVR();
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
+AVR::AVR() { NoneRel = R_AVR_NONE; }
+
RelExpr AVR::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
return R_ABS;
diff --git a/ELF/Arch/Hexagon.cpp b/ELF/Arch/Hexagon.cpp
index ff5e862bafa2..b4d33be2ad39 100644
--- a/ELF/Arch/Hexagon.cpp
+++ b/ELF/Arch/Hexagon.cpp
@@ -9,6 +9,7 @@
#include "InputFiles.h"
#include "Symbols.h"
+#include "SyntheticSections.h"
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -25,15 +26,48 @@ using namespace lld::elf;
namespace {
class Hexagon final : public TargetInfo {
public:
+ Hexagon();
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;
+ 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
-// Support V60 only at the moment.
-uint32_t Hexagon::calcEFlags() const { return 0x60; }
+Hexagon::Hexagon() {
+ PltRel = R_HEX_JMP_SLOT;
+ RelativeRel = R_HEX_RELATIVE;
+ GotRel = R_HEX_GLOB_DAT;
+ GotEntrySize = 4;
+ // The zero'th GOT entry is reserved for the address of _DYNAMIC. The
+ // next 3 are reserved for the dynamic loader.
+ GotPltHeaderEntriesNum = 4;
+ GotPltEntrySize = 4;
+
+ PltEntrySize = 16;
+ PltHeaderSize = 32;
+
+ // Hexagon Linux uses 64K pages by default.
+ DefaultMaxPageSize = 0x10000;
+ NoneRel = R_HEX_NONE;
+}
+
+uint32_t Hexagon::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ // The architecture revision must always be equal to or greater than
+ // greatest revision in the list of inputs.
+ uint32_t Ret = 0;
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+ if (EFlags > Ret)
+ Ret = EFlags;
+ }
+ return Ret;
+}
static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
uint32_t Result = 0;
@@ -53,29 +87,143 @@ static uint32_t applyMask(uint32_t Mask, uint32_t Data) {
RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_HEX_B9_PCREL:
+ case R_HEX_B9_PCREL_X:
+ case R_HEX_B13_PCREL:
case R_HEX_B15_PCREL:
case R_HEX_B15_PCREL_X:
+ case R_HEX_6_PCREL_X:
+ case R_HEX_32_PCREL:
+ return R_PC;
case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
case R_HEX_B22_PCREL_X:
case R_HEX_B32_PCREL_X:
- return R_PC;
+ return R_PLT_PC;
+ case R_HEX_GOT_11_X:
+ case R_HEX_GOT_16_X:
+ case R_HEX_GOT_32_6_X:
+ return R_HEXAGON_GOT;
default:
return R_ABS;
}
}
+static uint32_t findMaskR6(uint32_t Insn) {
+ // There are (arguably too) many relocation masks for the DSP's
+ // R_HEX_6_X type. The table below is used to select the correct mask
+ // for the given instruction.
+ struct InstructionMask {
+ uint32_t CmpMask;
+ uint32_t RelocMask;
+ };
+
+ static const InstructionMask R6[] = {
+ {0x38000000, 0x0000201f}, {0x39000000, 0x0000201f},
+ {0x3e000000, 0x00001f80}, {0x3f000000, 0x00001f80},
+ {0x40000000, 0x000020f8}, {0x41000000, 0x000007e0},
+ {0x42000000, 0x000020f8}, {0x43000000, 0x000007e0},
+ {0x44000000, 0x000020f8}, {0x45000000, 0x000007e0},
+ {0x46000000, 0x000020f8}, {0x47000000, 0x000007e0},
+ {0x6a000000, 0x00001f80}, {0x7c000000, 0x001f2000},
+ {0x9a000000, 0x00000f60}, {0x9b000000, 0x00000f60},
+ {0x9c000000, 0x00000f60}, {0x9d000000, 0x00000f60},
+ {0x9f000000, 0x001f0100}, {0xab000000, 0x0000003f},
+ {0xad000000, 0x0000003f}, {0xaf000000, 0x00030078},
+ {0xd7000000, 0x006020e0}, {0xd8000000, 0x006020e0},
+ {0xdb000000, 0x006020e0}, {0xdf000000, 0x006020e0}};
+
+ // Duplex forms have a fixed mask and parse bits 15:14 are always
+ // zero. Non-duplex insns will always have at least one bit set in the
+ // parse field.
+ if ((0xC000 & Insn) == 0x0)
+ return 0x03f00000;
+
+ for (InstructionMask I : R6)
+ if ((0xff000000 & Insn) == I.CmpMask)
+ return I.RelocMask;
+
+ error("unrecognized instruction for R_HEX_6 relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
+static uint32_t findMaskR8(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xde000000)
+ return 0x00e020e8;
+ if ((0xff000000 & Insn) == 0x3c000000)
+ return 0x0000207f;
+ return 0x00001fe0;
+}
+
+static uint32_t findMaskR11(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0xa1000000)
+ return 0x060020ff;
+ return 0x06003fe0;
+}
+
+static uint32_t findMaskR16(uint32_t Insn) {
+ if ((0xff000000 & Insn) == 0x48000000)
+ return 0x061f20ff;
+ if ((0xff000000 & Insn) == 0x49000000)
+ return 0x061f3fe0;
+ if ((0xff000000 & Insn) == 0x78000000)
+ return 0x00df3fe0;
+ if ((0xff000000 & Insn) == 0xb0000000)
+ return 0x0fe03fe0;
+
+ error("unrecognized instruction for R_HEX_16_X relocation: 0x" +
+ utohexstr(Insn));
+ return 0;
+}
+
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_6_PCREL_X:
+ case R_HEX_6_X:
+ or32le(Loc, applyMask(findMaskR6(read32le(Loc)), Val));
+ break;
+ case R_HEX_8_X:
+ or32le(Loc, applyMask(findMaskR8(read32le(Loc)), Val));
+ break;
+ case R_HEX_9_X:
+ or32le(Loc, applyMask(0x00003fe0, Val & 0x3f));
+ break;
+ case R_HEX_10_X:
+ or32le(Loc, applyMask(0x00203fe0, Val & 0x3f));
+ break;
+ case R_HEX_11_X:
+ case R_HEX_GOT_11_X:
+ or32le(Loc, applyMask(findMaskR11(read32le(Loc)), Val & 0x3f));
+ break;
case R_HEX_12_X:
or32le(Loc, applyMask(0x000007e0, Val));
break;
+ case R_HEX_16_X: // These relocs only have 6 effective bits.
+ case R_HEX_GOT_16_X:
+ or32le(Loc, applyMask(findMaskR16(read32le(Loc)), Val & 0x3f));
+ break;
+ case R_HEX_32:
+ case R_HEX_32_PCREL:
+ or32le(Loc, Val);
+ break;
case R_HEX_32_6_X:
+ case R_HEX_GOT_32_6_X:
or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
break;
+ case R_HEX_B9_PCREL:
+ or32le(Loc, applyMask(0x003000fe, Val >> 2));
+ break;
+ case R_HEX_B9_PCREL_X:
+ or32le(Loc, applyMask(0x003000fe, Val & 0x3f));
+ break;
+ case R_HEX_B13_PCREL:
+ or32le(Loc, applyMask(0x00202ffe, Val >> 2));
+ break;
case R_HEX_B15_PCREL:
or32le(Loc, applyMask(0x00df20fe, Val >> 2));
break;
@@ -83,6 +231,7 @@ void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
or32le(Loc, applyMask(0x00df20fe, Val & 0x3f));
break;
case R_HEX_B22_PCREL:
+ case R_HEX_PLT_B22_PCREL:
or32le(Loc, applyMask(0x1ff3ffe, Val >> 2));
break;
case R_HEX_B22_PCREL_X:
@@ -91,12 +240,52 @@ void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_HEX_B32_PCREL_X:
or32le(Loc, applyMask(0x0fff3fff, Val >> 6));
break;
+ case R_HEX_HI16:
+ or32le(Loc, applyMask(0x00c03fff, Val >> 16));
+ break;
+ case R_HEX_LO16:
+ or32le(Loc, applyMask(0x00c03fff, Val));
+ break;
default:
error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
break;
}
}
+void Hexagon::writePltHeader(uint8_t *Buf) const {
+ const uint8_t PltData[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # @GOT0
+ 0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn
+ 0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
+ 0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
+ 0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
+ 0x0c, 0xdb, 0x00, 0x54, // trap0(#0xdb) # bring plt0 into 16byte alignment
+ };
+ memcpy(Buf, PltData, sizeof(PltData));
+
+ // Offset from PLT0 to the GOT.
+ uint64_t Off = In.GotPlt->getVA() - In.Plt->getVA();
+ relocateOne(Buf, R_HEX_B32_PCREL_X, Off);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, Off);
+}
+
+void Hexagon::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ const uint8_t Inst[] = {
+ 0x00, 0x40, 0x00, 0x00, // { immext (#0)
+ 0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) }
+ 0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14)
+ 0x00, 0xc0, 0x9c, 0x52, // jumpr r28
+ };
+ memcpy(Buf, Inst, sizeof(Inst));
+
+ relocateOne(Buf, R_HEX_B32_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+ relocateOne(Buf + 4, R_HEX_6_PCREL_X, GotPltEntryAddr - PltEntryAddr);
+}
+
TargetInfo *elf::getHexagonTargetInfo() {
static Hexagon Target;
return &Target;
diff --git a/ELF/Arch/MSP430.cpp b/ELF/Arch/MSP430.cpp
new file mode 100644
index 000000000000..fe0c0fe64daf
--- /dev/null
+++ b/ELF/Arch/MSP430.cpp
@@ -0,0 +1,94 @@
+//===- MSP430.cpp ---------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The MSP430 is a 16-bit microcontroller RISC architecture. The instruction set
+// has only 27 core instructions orthogonally augmented with a variety
+// of addressing modes for source and destination operands. Entire address space
+// of MSP430 is 64KB (the extended MSP430X architecture is not considered here).
+// A typical MSP430 MCU has several kilobytes of RAM and ROM, plenty
+// of peripherals and is generally optimized for a low power consumption.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "lld/Common/ErrorHandler.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 MSP430 final : public TargetInfo {
+public:
+ MSP430();
+ 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
+
+MSP430::MSP430() {
+ // mov.b #0, r3
+ TrapInstr = {0x43, 0x43, 0x43, 0x43};
+}
+
+RelExpr MSP430::getRelExpr(RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_MSP430_10_PCREL:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_PCREL_BYTE:
+ case R_MSP430_2X_PCREL:
+ case R_MSP430_RL_PCREL:
+ case R_MSP430_SYM_DIFF:
+ return R_PC;
+ default:
+ return R_ABS;
+ }
+}
+
+void MSP430::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ switch (Type) {
+ case R_MSP430_8:
+ checkIntUInt(Loc, Val, 8, Type);
+ *Loc = Val;
+ break;
+ case R_MSP430_16:
+ case R_MSP430_16_PCREL:
+ case R_MSP430_16_BYTE:
+ case R_MSP430_16_PCREL_BYTE:
+ checkIntUInt(Loc, Val, 16, Type);
+ write16le(Loc, Val);
+ break;
+ case R_MSP430_32:
+ checkIntUInt(Loc, Val, 32, Type);
+ write32le(Loc, Val);
+ break;
+ case R_MSP430_10_PCREL: {
+ int16_t Offset = ((int16_t)Val >> 1) - 1;
+ checkInt(Loc, Offset, 10, Type);
+ write16le(Loc, (read16le(Loc) & 0xFC00) | (Offset & 0x3FF));
+ break;
+ }
+ default:
+ error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type));
+ }
+}
+
+TargetInfo *elf::getMSP430TargetInfo() {
+ static MSP430 Target;
+ return &Target;
+}
diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp
index dc70401c0b0e..23b0c1dd8a2d 100644
--- a/ELF/Arch/Mips.cpp
+++ b/ELF/Arch/Mips.cpp
@@ -53,9 +53,12 @@ template <class ELFT> MIPS<ELFT>::MIPS() {
PltEntrySize = 16;
PltHeaderSize = 32;
CopyRel = R_MIPS_COPY;
+ NoneRel = R_MIPS_NONE;
PltRel = R_MIPS_JUMP_SLOT;
NeedsThunks = true;
- TrapInstr = 0xefefefef;
+
+ // Set `sigrie 1` as a trap instruction.
+ write32(TrapInstr.data(), 0x04170001);
if (ELFT::Is64Bits) {
RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32;
@@ -185,7 +188,7 @@ template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const {
template <class ELFT>
void MIPS<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &) const {
- uint64_t VA = InX::Plt->getVA();
+ uint64_t VA = In.Plt->getVA();
if (isMicroMips())
VA |= 1;
write32<ELFT::TargetEndianness>(Buf, VA);
@@ -239,8 +242,8 @@ static void writeMicroRelocation16(uint8_t *Loc, uint64_t V, uint8_t BitsSize,
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
const endianness E = ELFT::TargetEndianness;
if (isMicroMips()) {
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(Buf, 0, PltHeaderSize);
@@ -292,7 +295,7 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const {
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();
+ uint64_t GotPlt = In.GotPlt->getVA();
writeValue<E>(Buf, GotPlt + 0x8000, 16, 16);
writeValue<E>(Buf + 4, GotPlt, 16, 0);
writeValue<E>(Buf + 8, GotPlt, 16, 0);
diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp
index 20cae0e59cf4..767378067341 100644
--- a/ELF/Arch/PPC.cpp
+++ b/ELF/Arch/PPC.cpp
@@ -29,6 +29,7 @@ public:
} // namespace
PPC::PPC() {
+ NoneRel = R_PPC_NONE;
GotBaseSymOff = 0x8000;
GotBaseSymInGotPlt = false;
}
@@ -36,6 +37,7 @@ PPC::PPC() {
RelExpr PPC::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_PPC_REL14:
case R_PPC_REL24:
case R_PPC_REL32:
return R_PC;
@@ -61,6 +63,9 @@ void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC_REL32:
write32be(Loc, Val);
break;
+ case R_PPC_REL14:
+ write32be(Loc, read32be(Loc) | (Val & 0xFFFC));
+ break;
case R_PPC_PLTREL24:
case R_PPC_REL24:
write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC));
diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp
index fa3bf6c62a0d..8a320c9a4e9e 100644
--- a/ELF/Arch/PPC64.cpp
+++ b/ELF/Arch/PPC64.cpp
@@ -23,12 +23,49 @@ using namespace lld::elf;
static uint64_t PPC64TocOffset = 0x8000;
static uint64_t DynamicThreadPointerOffset = 0x8000;
+// The instruction encoding of bits 21-30 from the ISA for the Xform and Dform
+// instructions that can be used as part of the initial exec TLS sequence.
+enum XFormOpcd {
+ LBZX = 87,
+ LHZX = 279,
+ LWZX = 23,
+ LDX = 21,
+ STBX = 215,
+ STHX = 407,
+ STWX = 151,
+ STDX = 149,
+ ADD = 266,
+};
+
+enum DFormOpcd {
+ LBZ = 34,
+ LBZU = 35,
+ LHZ = 40,
+ LHZU = 41,
+ LHAU = 43,
+ LWZ = 32,
+ LWZU = 33,
+ LFSU = 49,
+ LD = 58,
+ LFDU = 51,
+ STB = 38,
+ STBU = 39,
+ STH = 44,
+ STHU = 45,
+ STW = 36,
+ STWU = 37,
+ STFSU = 53,
+ STFDU = 55,
+ STD = 62,
+ ADDI = 14
+};
+
uint64_t elf::getPPC64TocBase() {
// The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The
// TOC starts where the first of these sections starts. We always create a
// .got when we see a relocation that uses it, so for us the start is always
// the .got.
- uint64_t TocVA = InX::Got->getVA();
+ uint64_t TocVA = In.Got->getVA();
// Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
// thus permitting a full 64 Kbytes segment. Note that the glibc startup
@@ -37,6 +74,31 @@ uint64_t elf::getPPC64TocBase() {
return TocVA + PPC64TocOffset;
}
+unsigned elf::getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther) {
+ // The offset is encoded into the 3 most significant bits of the st_other
+ // field, with some special values described in section 3.4.1 of the ABI:
+ // 0 --> Zero offset between the GEP and LEP, and the function does NOT use
+ // the TOC pointer (r2). r2 will hold the same value on returning from
+ // the function as it did on entering the function.
+ // 1 --> Zero offset between the GEP and LEP, and r2 should be treated as a
+ // caller-saved register for all callers.
+ // 2-6 --> The binary logarithm of the offset eg:
+ // 2 --> 2^2 = 4 bytes --> 1 instruction.
+ // 6 --> 2^6 = 64 bytes --> 16 instructions.
+ // 7 --> Reserved.
+ uint8_t GepToLep = (StOther >> 5) & 7;
+ if (GepToLep < 2)
+ return 0;
+
+ // The value encoded in the st_other bits is the
+ // log-base-2(offset).
+ if (GepToLep < 7)
+ return 1 << GepToLep;
+
+ error("reserved value of 7 in the 3 most-significant-bits of st_other");
+ return 0;
+}
+
namespace {
class PPC64 final : public TargetInfo {
public:
@@ -51,11 +113,16 @@ public:
void writeGotHeader(uint8_t *Buf) const override;
bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
uint64_t BranchAddr, const Symbol &S) const override;
+ bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) 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;
+ void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
+
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
};
} // namespace
@@ -71,8 +138,64 @@ 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; }
+// Extracts the 'PO' field of an instruction encoding.
+static uint8_t getPrimaryOpCode(uint32_t Encoding) { return (Encoding >> 26); }
+
+static bool isDQFormInstruction(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case 56:
+ // The only instruction with a primary opcode of 56 is `lq`.
+ return true;
+ case 61:
+ // There are both DS and DQ instruction forms with this primary opcode.
+ // Namely `lxv` and `stxv` are the DQ-forms that use it.
+ // The DS 'XO' bits being set to 01 is restricted to DQ form.
+ return (Encoding & 3) == 0x1;
+ }
+}
+
+static bool isInstructionUpdateForm(uint32_t Encoding) {
+ switch (getPrimaryOpCode(Encoding)) {
+ default:
+ return false;
+ case LBZU:
+ case LHAU:
+ case LHZU:
+ case LWZU:
+ case LFSU:
+ case LFDU:
+ case STBU:
+ case STHU:
+ case STWU:
+ case STFSU:
+ case STFDU:
+ return true;
+ // LWA has the same opcode as LD, and the DS bits is what differentiates
+ // between LD/LDU/LWA
+ case LD:
+ case STD:
+ return (Encoding & 3) == 1;
+ }
+}
+
+// There are a number of places when we either want to read or write an
+// instruction when handling a half16 relocation type. On big-endian the buffer
+// pointer is pointing into the middle of the word we want to extract, and on
+// little-endian it is pointing to the start of the word. These 2 helpers are to
+// simplify reading and writing in that context.
+static void writeInstrFromHalf16(uint8_t *Loc, uint32_t Instr) {
+ write32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0), Instr);
+}
+
+static uint32_t readInstrFromHalf16(const uint8_t *Loc) {
+ return read32(Loc - (Config->EKind == ELF64BEKind ? 2 : 0));
+}
+
PPC64::PPC64() {
GotRel = R_PPC64_GLOB_DAT;
+ NoneRel = R_PPC64_NONE;
PltRel = R_PPC64_JMP_SLOT;
RelativeRel = R_PPC64_RELATIVE;
IRelativeRel = R_PPC64_IRELATIVE;
@@ -85,14 +208,14 @@ PPC64::PPC64() {
GotPltHeaderEntriesNum = 2;
PltHeaderSize = 60;
NeedsThunks = true;
- TcbSize = 8;
- TlsTpOffset = 0x7000;
TlsModuleIndexRel = R_PPC64_DTPMOD64;
TlsOffsetRel = R_PPC64_DTPREL64;
TlsGotRel = R_PPC64_TPREL64;
+ NeedsMoreStackNonSplit = false;
+
// We need 64K pages (at least under glibc/Linux, the loader won't
// set different permissions on a finer granularity than that).
DefaultMaxPageSize = 65536;
@@ -107,8 +230,7 @@ PPC64::PPC64() {
// use 0x10000000 as the starting address.
DefaultImageBase = 0x10000000;
- TrapInstr =
- (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f;
+ write32(TrapInstr.data(), 0x7fe00008);
}
static uint32_t getEFlags(InputFile *File) {
@@ -146,27 +268,29 @@ void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// 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
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
+ case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
- write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13
+ writeInstrFromHalf16(Loc, 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);
+ // Since we are relocating a half16 type relocation and Loc + 4 points to
+ // the start of an instruction we need to advance the buffer by an extra
+ // 2 bytes on BE.
+ relocateOne(Loc + 4 + (Config->EKind == ELF64BEKind ? 2 : 0),
+ 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:
@@ -183,13 +307,12 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
// 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
+ writeInstrFromHalf16(Loc, 0x60000000); // nop
break;
case R_PPC64_GOT_TLSLD16_LO:
- write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0
+ writeInstrFromHalf16(Loc, 0x3c6d0000); // addis r3, r13, 0
break;
case R_PPC64_TLSLD:
write32(Loc, 0x60000000); // nop
@@ -212,9 +335,90 @@ void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
}
+static unsigned getDFormOp(unsigned SecondaryOp) {
+ switch (SecondaryOp) {
+ case LBZX:
+ return LBZ;
+ case LHZX:
+ return LHZ;
+ case LWZX:
+ return LWZ;
+ case LDX:
+ return LD;
+ case STBX:
+ return STB;
+ case STHX:
+ return STH;
+ case STWX:
+ return STW;
+ case STDX:
+ return STD;
+ case ADD:
+ return ADDI;
+ default:
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ return 0;
+ }
+}
+
+void PPC64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const {
+ // The initial exec code sequence for a global `x` will look like:
+ // Instruction Relocation Symbol
+ // addis r9, r2, x@got@tprel@ha R_PPC64_GOT_TPREL16_HA x
+ // ld r9, x@got@tprel@l(r9) R_PPC64_GOT_TPREL16_LO_DS x
+ // add r9, r9, x@tls R_PPC64_TLS x
+
+ // Relaxing to local exec entails converting:
+ // addis r9, r2, x@got@tprel@ha into nop
+ // ld r9, x@got@tprel@l(r9) into addis r9, r13, x@tprel@ha
+ // add r9, r9, x@tls into addi r9, r9, x@tprel@l
+
+ // x@tls R_PPC64_TLS is a relocation which does not compute anything,
+ // it is replaced with r13 (thread pointer).
+
+ // The add instruction in the initial exec sequence has multiple variations
+ // that need to be handled. If we are building an address it will use an add
+ // instruction, if we are accessing memory it will use any of the X-form
+ // indexed load or store instructions.
+
+ unsigned Offset = (Config->EKind == ELF64BEKind) ? 2 : 0;
+ switch (Type) {
+ case R_PPC64_GOT_TPREL16_HA:
+ write32(Loc - Offset, 0x60000000); // nop
+ break;
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_TPREL16_DS: {
+ uint32_t RegNo = read32(Loc - Offset) & 0x03E00000; // bits 6-10
+ write32(Loc - Offset, 0x3C0D0000 | RegNo); // addis RegNo, r13
+ relocateOne(Loc, R_PPC64_TPREL16_HA, Val);
+ break;
+ }
+ case R_PPC64_TLS: {
+ uint32_t PrimaryOp = getPrimaryOpCode(read32(Loc));
+ if (PrimaryOp != 31)
+ error("unrecognized instruction for IE to LE R_PPC64_TLS");
+ uint32_t SecondaryOp = (read32(Loc) & 0x000007FE) >> 1; // bits 21-30
+ uint32_t DFormOp = getDFormOp(SecondaryOp);
+ write32(Loc, ((DFormOp << 26) | (read32(Loc) & 0x03FFFFFF)));
+ relocateOne(Loc + Offset, R_PPC64_TPREL16_LO, Val);
+ break;
+ }
+ default:
+ llvm_unreachable("unknown relocation for IE to LE");
+ break;
+ }
+}
+
RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
const uint8_t *Loc) const {
switch (Type) {
+ case R_PPC64_GOT16:
+ case R_PPC64_GOT16_DS:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_HI:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ return R_GOT_OFF;
case R_PPC64_TOC16:
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_HA:
@@ -224,6 +428,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
return R_GOTREL;
case R_PPC64_TOC:
return R_PPC_TOC;
+ case R_PPC64_REL14:
case R_PPC64_REL24:
return R_PPC_CALL_PLT;
case R_PPC64_REL16_LO:
@@ -279,7 +484,7 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S,
case R_PPC64_TLSLD:
return R_TLSLD_HINT;
case R_PPC64_TLS:
- return R_HINT;
+ return R_TLSIE_HINT;
default:
return R_ABS;
}
@@ -308,16 +513,16 @@ void PPC64::writePltHeader(uint8_t *Buf) const {
// 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);
+ int64_t GotPltOffset = In.GotPlt->getVA() - (In.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 {
- int32_t Offset = PltHeaderSize + Index * PltEntrySize;
- // bl __glink_PLTresolve
- write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
+ 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) {
@@ -328,30 +533,36 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
switch (Type) {
// TOC biased relocation.
+ case R_PPC64_GOT16:
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSLD16:
case R_PPC64_TOC16:
return {R_PPC64_ADDR16, TocBiasedVal};
+ case R_PPC64_GOT16_DS:
case R_PPC64_TOC16_DS:
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_DTPREL16_DS:
return {R_PPC64_ADDR16_DS, TocBiasedVal};
+ case R_PPC64_GOT16_HA:
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, TocBiasedVal};
+ case R_PPC64_GOT16_HI:
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, TocBiasedVal};
+ case R_PPC64_GOT16_LO:
case R_PPC64_GOT_TLSGD16_LO:
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_TOC16_LO:
return {R_PPC64_ADDR16_LO, TocBiasedVal};
+ case R_PPC64_GOT16_LO_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_DTPREL16_LO_DS:
@@ -386,9 +597,27 @@ static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
}
}
+static bool isTocOptType(RelType Type) {
+ switch (Type) {
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ return true;
+ default:
+ return false;
+ }
+}
+
void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
- // For a TOC-relative relocation, proceed in terms of the corresponding
- // ADDR16 relocation type.
+ // We need to save the original relocation type to use in diagnostics, and
+ // use the original type to determine if we should toc-optimize the
+ // instructions being relocated.
+ RelType OriginalType = Type;
+ bool ShouldTocOptimize = isTocOptType(Type);
+ // For dynamic thread pointer relative, toc-relative, and got-indirect
+ // relocations, proceed in terms of the corresponding ADDR16 relocation type.
std::tie(Type, Val) = toAddr16Rel(Type, Val);
switch (Type) {
@@ -401,18 +630,25 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
case R_PPC64_ADDR16:
case R_PPC64_TPREL16:
- checkInt(Loc, Val, 16, Type);
+ checkInt(Loc, Val, 16, OriginalType);
write16(Loc, Val);
break;
case R_PPC64_ADDR16_DS:
- case R_PPC64_TPREL16_DS:
- checkInt(Loc, Val, 16, Type);
- write16(Loc, (read16(Loc) & 3) | (Val & ~3));
- break;
+ case R_PPC64_TPREL16_DS: {
+ checkInt(Loc, Val, 16, OriginalType);
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint16_t Mask = isDQFormInstruction(readInstrFromHalf16(Loc)) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR16_HA:
case R_PPC64_REL16_HA:
case R_PPC64_TPREL16_HA:
- write16(Loc, ha(Val));
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0)
+ writeInstrFromHalf16(Loc, 0x60000000);
+ else
+ write16(Loc, ha(Val));
break;
case R_PPC64_ADDR16_HI:
case R_PPC64_REL16_HI:
@@ -438,12 +674,40 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC64_ADDR16_LO:
case R_PPC64_REL16_LO:
case R_PPC64_TPREL16_LO:
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the
+ // toc-pointer register r2, as the base register.
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ uint32_t Instr = readInstrFromHalf16(Loc);
+ if (isInstructionUpdateForm(Instr))
+ error(getErrorLocation(Loc) +
+ "can't toc-optimize an update instruction: 0x" +
+ utohexstr(Instr));
+ Instr = (Instr & 0xFFE00000) | 0x00020000;
+ writeInstrFromHalf16(Loc, Instr);
+ }
write16(Loc, lo(Val));
break;
case R_PPC64_ADDR16_LO_DS:
- case R_PPC64_TPREL16_LO_DS:
- write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3));
- break;
+ case R_PPC64_TPREL16_LO_DS: {
+ // DQ-form instructions use bits 28-31 as part of the instruction encoding
+ // DS-form instructions only use bits 30-31.
+ uint32_t Inst = readInstrFromHalf16(Loc);
+ uint16_t Mask = isDQFormInstruction(Inst) ? 0xF : 0x3;
+ checkAlignment(Loc, lo(Val), Mask + 1, OriginalType);
+ if (Config->TocOptimize && ShouldTocOptimize && ha(Val) == 0) {
+ // When the high-adjusted part of a toc relocation evalutes to 0, it is
+ // changed into a nop. The lo part then needs to be updated to use the toc
+ // pointer register r2, as the base register.
+ if (isInstructionUpdateForm(Inst))
+ error(getErrorLocation(Loc) +
+ "Can't toc-optimize an update instruction: 0x" +
+ Twine::utohexstr(Inst));
+ Inst = (Inst & 0xFFE0000F) | 0x00020000;
+ writeInstrFromHalf16(Loc, Inst);
+ }
+ write16(Loc, (read16(Loc) & Mask) | lo(Val));
+ } break;
case R_PPC64_ADDR32:
case R_PPC64_REL32:
checkInt(Loc, Val, 32, Type);
@@ -454,9 +718,17 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_PPC64_TOC:
write64(Loc, Val);
break;
+ case R_PPC64_REL14: {
+ uint32_t Mask = 0x0000FFFC;
+ checkInt(Loc, Val, 16, Type);
+ checkAlignment(Loc, Val, 4, Type);
+ write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
+ break;
+ }
case R_PPC64_REL24: {
uint32_t Mask = 0x03FFFFFC;
- checkInt(Loc, Val, 24, Type);
+ checkInt(Loc, Val, 26, Type);
+ checkAlignment(Loc, Val, 4, Type);
write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask));
break;
}
@@ -470,9 +742,30 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
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();
+ if (Type != R_PPC64_REL14 && Type != R_PPC64_REL24)
+ return false;
+
+ // If a function is in the Plt it needs to be called with a call-stub.
+ if (S.isInPlt())
+ return true;
+
+ // If a symbol is a weak undefined and we are compiling an executable
+ // it doesn't need a range-extending thunk since it can't be called.
+ if (S.isUndefWeak() && !Config->Shared)
+ return false;
+
+ // If the offset exceeds the range of the branch type then it will need
+ // a range-extending thunk.
+ return !inBranchRange(Type, BranchAddr, S.getVA());
+}
+
+bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+ int64_t Offset = Dst - Src;
+ if (Type == R_PPC64_REL14)
+ return isInt<16>(Offset);
+ if (Type == R_PPC64_REL24)
+ return isInt<26>(Offset);
+ llvm_unreachable("unsupported relocation type used in branch");
}
RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,
@@ -511,9 +804,8 @@ void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
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);
+ uint32_t InputRegister = (readInstrFromHalf16(Loc) & (0x1f << 16));
+ writeInstrFromHalf16(Loc, 0xE8600000 | InputRegister);
relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val);
return;
}
@@ -526,6 +818,113 @@ void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const {
}
}
+// The prologue for a split-stack function is expected to look roughly
+// like this:
+// .Lglobal_entry_point:
+// # TOC pointer initalization.
+// ...
+// .Llocal_entry_point:
+// # load the __private_ss member of the threads tcbhead.
+// ld r0,-0x7000-64(r13)
+// # subtract the functions stack size from the stack pointer.
+// addis r12, r1, ha(-stack-frame size)
+// addi r12, r12, l(-stack-frame size)
+// # compare needed to actual and branch to allocate_more_stack if more
+// # space is needed, otherwise fallthrough to 'normal' function body.
+// cmpld cr7,r12,r0
+// blt- cr7, .Lallocate_more_stack
+//
+// -) The allocate_more_stack block might be placed after the split-stack
+// prologue and the `blt-` replaced with a `bge+ .Lnormal_func_body`
+// instead.
+// -) If either the addis or addi is not needed due to the stack size being
+// smaller then 32K or a multiple of 64K they will be replaced with a nop,
+// but there will always be 2 instructions the linker can overwrite for the
+// adjusted stack size.
+//
+// The linkers job here is to increase the stack size used in the addis/addi
+// pair by split-stack-size-adjust.
+// addis r12, r1, ha(-stack-frame size - split-stack-adjust-size)
+// addi r12, r12, l(-stack-frame size - split-stack-adjust-size)
+bool PPC64::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const {
+ // If the caller has a global entry point adjust the buffer past it. The start
+ // of the split-stack prologue will be at the local entry point.
+ Loc += getPPC64GlobalEntryToLocalEntryOffset(StOther);
+
+ // At the very least we expect to see a load of some split-stack data from the
+ // tcb, and 2 instructions that calculate the ending stack address this
+ // function will require. If there is not enough room for at least 3
+ // instructions it can't be a split-stack prologue.
+ if (Loc + 12 >= End)
+ return false;
+
+ // First instruction must be `ld r0, -0x7000-64(r13)`
+ if (read32(Loc) != 0xe80d8fc0)
+ return false;
+
+ int16_t HiImm = 0;
+ int16_t LoImm = 0;
+ // First instruction can be either an addis if the frame size is larger then
+ // 32K, or an addi if the size is less then 32K.
+ int32_t FirstInstr = read32(Loc + 4);
+ if (getPrimaryOpCode(FirstInstr) == 15) {
+ HiImm = FirstInstr & 0xFFFF;
+ } else if (getPrimaryOpCode(FirstInstr) == 14) {
+ LoImm = FirstInstr & 0xFFFF;
+ } else {
+ return false;
+ }
+
+ // Second instruction is either an addi or a nop. If the first instruction was
+ // an addi then LoImm is set and the second instruction must be a nop.
+ uint32_t SecondInstr = read32(Loc + 8);
+ if (!LoImm && getPrimaryOpCode(SecondInstr) == 14) {
+ LoImm = SecondInstr & 0xFFFF;
+ } else if (SecondInstr != 0x60000000) {
+ return false;
+ }
+
+ // The register operands of the first instruction should be the stack-pointer
+ // (r1) as the input (RA) and r12 as the output (RT). If the second
+ // instruction is not a nop, then it should use r12 as both input and output.
+ auto CheckRegOperands = [](uint32_t Instr, uint8_t ExpectedRT,
+ uint8_t ExpectedRA) {
+ return ((Instr & 0x3E00000) >> 21 == ExpectedRT) &&
+ ((Instr & 0x1F0000) >> 16 == ExpectedRA);
+ };
+ if (!CheckRegOperands(FirstInstr, 12, 1))
+ return false;
+ if (SecondInstr != 0x60000000 && !CheckRegOperands(SecondInstr, 12, 12))
+ return false;
+
+ int32_t StackFrameSize = (HiImm * 65536) + LoImm;
+ // Check that the adjusted size doesn't overflow what we can represent with 2
+ // instructions.
+ if (StackFrameSize < Config->SplitStackAdjustSize + INT32_MIN) {
+ error(getErrorLocation(Loc) + "split-stack prologue adjustment overflows");
+ return false;
+ }
+
+ int32_t AdjustedStackFrameSize =
+ StackFrameSize - Config->SplitStackAdjustSize;
+
+ LoImm = AdjustedStackFrameSize & 0xFFFF;
+ HiImm = (AdjustedStackFrameSize + 0x8000) >> 16;
+ if (HiImm) {
+ write32(Loc + 4, 0x3D810000 | (uint16_t)HiImm);
+ // If the low immediate is zero the second instruction will be a nop.
+ SecondInstr = LoImm ? 0x398C0000 | (uint16_t)LoImm : 0x60000000;
+ write32(Loc + 8, SecondInstr);
+ } else {
+ // addi r12, r1, imm
+ write32(Loc + 4, (0x39810000) | (uint16_t)LoImm);
+ write32(Loc + 8, 0x60000000);
+ }
+
+ return true;
+}
+
TargetInfo *elf::getPPC64TargetInfo() {
static PPC64 Target;
return &Target;
diff --git a/ELF/Arch/RISCV.cpp b/ELF/Arch/RISCV.cpp
new file mode 100644
index 000000000000..461e8d35c3e6
--- /dev/null
+++ b/ELF/Arch/RISCV.cpp
@@ -0,0 +1,279 @@
+//===- RISCV.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 "Target.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 RISCV final : public TargetInfo {
+public:
+ RISCV();
+ 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;
+};
+
+} // end anonymous namespace
+
+RISCV::RISCV() { NoneRel = R_RISCV_NONE; }
+
+static uint32_t getEFlags(InputFile *F) {
+ if (Config->Is64)
+ return cast<ObjFile<ELF64LE>>(F)->getObj().getHeader()->e_flags;
+ return cast<ObjFile<ELF32LE>>(F)->getObj().getHeader()->e_flags;
+}
+
+uint32_t RISCV::calcEFlags() const {
+ assert(!ObjectFiles.empty());
+
+ uint32_t Target = getEFlags(ObjectFiles.front());
+
+ for (InputFile *F : ObjectFiles) {
+ uint32_t EFlags = getEFlags(F);
+ if (EFlags & EF_RISCV_RVC)
+ Target |= EF_RISCV_RVC;
+
+ if ((EFlags & EF_RISCV_FLOAT_ABI) != (Target & EF_RISCV_FLOAT_ABI))
+ error(toString(F) +
+ ": cannot link object files with different floating-point ABI");
+
+ if ((EFlags & EF_RISCV_RVE) != (Target & EF_RISCV_RVE))
+ error(toString(F) +
+ ": cannot link object files with different EF_RISCV_RVE");
+ }
+
+ return Target;
+}
+
+RelExpr RISCV::getRelExpr(const RelType Type, const Symbol &S,
+ const uint8_t *Loc) const {
+ switch (Type) {
+ case R_RISCV_JAL:
+ case R_RISCV_BRANCH:
+ case R_RISCV_CALL:
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
+ case R_RISCV_32_PCREL:
+ return R_PC;
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ return R_RISCV_PC_INDIRECT;
+ case R_RISCV_RELAX:
+ case R_RISCV_ALIGN:
+ return R_HINT;
+ default:
+ return R_ABS;
+ }
+}
+
+// Extract bits V[Begin:End], where range is inclusive, and Begin must be < 63.
+static uint32_t extractBits(uint64_t V, uint32_t Begin, uint32_t End) {
+ return (V & ((1ULL << (Begin + 1)) - 1)) >> End;
+}
+
+void RISCV::relocateOne(uint8_t *Loc, const RelType Type,
+ const uint64_t Val) const {
+ switch (Type) {
+ case R_RISCV_32:
+ write32le(Loc, Val);
+ return;
+ case R_RISCV_64:
+ write64le(Loc, Val);
+ return;
+
+ case R_RISCV_RVC_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 8, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE383;
+ uint16_t Imm8 = extractBits(Val, 8, 8) << 12;
+ uint16_t Imm4_3 = extractBits(Val, 4, 3) << 10;
+ uint16_t Imm7_6 = extractBits(Val, 7, 6) << 5;
+ uint16_t Imm2_1 = extractBits(Val, 2, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm8 | Imm4_3 | Imm7_6 | Imm2_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_JUMP: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 11, Type);
+ checkAlignment(Loc, Val, 2, Type);
+ uint16_t Insn = read16le(Loc) & 0xE003;
+ uint16_t Imm11 = extractBits(Val, 11, 11) << 12;
+ uint16_t Imm4 = extractBits(Val, 4, 4) << 11;
+ uint16_t Imm9_8 = extractBits(Val, 9, 8) << 9;
+ uint16_t Imm10 = extractBits(Val, 10, 10) << 8;
+ uint16_t Imm6 = extractBits(Val, 6, 6) << 7;
+ uint16_t Imm7 = extractBits(Val, 7, 7) << 6;
+ uint16_t Imm3_1 = extractBits(Val, 3, 1) << 3;
+ uint16_t Imm5 = extractBits(Val, 5, 5) << 2;
+ Insn |= Imm11 | Imm4 | Imm9_8 | Imm10 | Imm6 | Imm7 | Imm3_1 | Imm5;
+
+ write16le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_RVC_LUI: {
+ int32_t Imm = ((Val + 0x800) >> 12);
+ checkUInt(Loc, Imm, 6, Type);
+ if (Imm == 0) { // `c.lui rd, 0` is illegal, convert to `c.li rd, 0`
+ write16le(Loc, (read16le(Loc) & 0x0F83) | 0x4000);
+ } else {
+ uint16_t Imm17 = extractBits(Val + 0x800, 17, 17) << 12;
+ uint16_t Imm16_12 = extractBits(Val + 0x800, 16, 12) << 2;
+ write16le(Loc, (read16le(Loc) & 0xEF83) | Imm17 | Imm16_12);
+ }
+ return;
+ }
+
+ case R_RISCV_JAL: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 20, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0xFFF;
+ uint32_t Imm20 = extractBits(Val, 20, 20) << 31;
+ uint32_t Imm10_1 = extractBits(Val, 10, 1) << 21;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 20;
+ uint32_t Imm19_12 = extractBits(Val, 19, 12) << 12;
+ Insn |= Imm20 | Imm10_1 | Imm11 | Imm19_12;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ case R_RISCV_BRANCH: {
+ checkInt(Loc, static_cast<int64_t>(Val) >> 1, 12, Type);
+ checkAlignment(Loc, Val, 2, Type);
+
+ uint32_t Insn = read32le(Loc) & 0x1FFF07F;
+ uint32_t Imm12 = extractBits(Val, 12, 12) << 31;
+ uint32_t Imm10_5 = extractBits(Val, 10, 5) << 25;
+ uint32_t Imm4_1 = extractBits(Val, 4, 1) << 8;
+ uint32_t Imm11 = extractBits(Val, 11, 11) << 7;
+ Insn |= Imm12 | Imm10_5 | Imm4_1 | Imm11;
+
+ write32le(Loc, Insn);
+ return;
+ }
+
+ // auipc + jalr pair
+ case R_RISCV_CALL: {
+ checkInt(Loc, Val, 32, Type);
+ if (isInt<32>(Val)) {
+ relocateOne(Loc, R_RISCV_PCREL_HI20, Val);
+ relocateOne(Loc + 4, R_RISCV_PCREL_LO12_I, Val);
+ }
+ return;
+ }
+
+ case R_RISCV_PCREL_HI20:
+ case R_RISCV_HI20: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ write32le(Loc, (read32le(Loc) & 0xFFF) | (Hi & 0xFFFFF000));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_LO12_I: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ write32le(Loc, (read32le(Loc) & 0xFFFFF) | ((Lo & 0xFFF) << 20));
+ return;
+ }
+
+ case R_RISCV_PCREL_LO12_S:
+ case R_RISCV_LO12_S: {
+ checkInt(Loc, Val, 32, Type);
+ uint32_t Hi = Val + 0x800;
+ uint32_t Lo = Val - (Hi & 0xFFFFF000);
+ uint32_t Imm11_5 = extractBits(Lo, 11, 5) << 25;
+ uint32_t Imm4_0 = extractBits(Lo, 4, 0) << 7;
+ write32le(Loc, (read32le(Loc) & 0x1FFF07F) | Imm11_5 | Imm4_0);
+ return;
+ }
+
+ case R_RISCV_ADD8:
+ *Loc += Val;
+ return;
+ case R_RISCV_ADD16:
+ write16le(Loc, read16le(Loc) + Val);
+ return;
+ case R_RISCV_ADD32:
+ write32le(Loc, read32le(Loc) + Val);
+ return;
+ case R_RISCV_ADD64:
+ write64le(Loc, read64le(Loc) + Val);
+ return;
+ case R_RISCV_SUB6:
+ *Loc = (*Loc & 0xc0) | (((*Loc & 0x3f) - Val) & 0x3f);
+ return;
+ case R_RISCV_SUB8:
+ *Loc -= Val;
+ return;
+ case R_RISCV_SUB16:
+ write16le(Loc, read16le(Loc) - Val);
+ return;
+ case R_RISCV_SUB32:
+ write32le(Loc, read32le(Loc) - Val);
+ return;
+ case R_RISCV_SUB64:
+ write64le(Loc, read64le(Loc) - Val);
+ return;
+ case R_RISCV_SET6:
+ *Loc = (*Loc & 0xc0) | (Val & 0x3f);
+ return;
+ case R_RISCV_SET8:
+ *Loc = Val;
+ return;
+ case R_RISCV_SET16:
+ write16le(Loc, Val);
+ return;
+ case R_RISCV_SET32:
+ case R_RISCV_32_PCREL:
+ write32le(Loc, Val);
+ return;
+
+ case R_RISCV_ALIGN:
+ case R_RISCV_RELAX:
+ return; // Ignored (for now)
+ case R_RISCV_NONE:
+ return; // Do nothing
+
+ // These are handled by the dynamic linker
+ case R_RISCV_RELATIVE:
+ case R_RISCV_COPY:
+ case R_RISCV_JUMP_SLOT:
+ // GP-relative relocations are only produced after relaxation, which
+ // we don't support for now
+ case R_RISCV_GPREL_I:
+ case R_RISCV_GPREL_S:
+ default:
+ error(getErrorLocation(Loc) +
+ "unimplemented relocation: " + toString(Type));
+ return;
+ }
+}
+
+TargetInfo *elf::getRISCVTargetInfo() {
+ static RISCV Target;
+ return &Target;
+}
diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp
index 36f5c836930e..831aa2028e7f 100644
--- a/ELF/Arch/SPARCV9.cpp
+++ b/ELF/Arch/SPARCV9.cpp
@@ -35,6 +35,7 @@ public:
SPARCV9::SPARCV9() {
CopyRel = R_SPARC_COPY;
GotRel = R_SPARC_GLOB_DAT;
+ NoneRel = R_SPARC_NONE;
PltRel = R_SPARC_JMP_SLOT;
RelativeRel = R_SPARC_RELATIVE;
GotEntrySize = 8;
diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp
index 19a0b6017f1a..e910375d2fc7 100644
--- a/ELF/Arch/X86.cpp
+++ b/ELF/Arch/X86.cpp
@@ -48,6 +48,7 @@ public:
X86::X86() {
CopyRel = R_386_COPY;
GotRel = R_386_GLOB_DAT;
+ NoneRel = R_386_NONE;
PltRel = R_386_JUMP_SLOT;
IRelativeRel = R_386_IRELATIVE;
RelativeRel = R_386_RELATIVE;
@@ -59,7 +60,11 @@ X86::X86() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
- TrapInstr = 0xcccccccc; // 0xcc = INT3
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
+
+ // Align to the non-PAE large page size (known as a superpage or huge page).
+ // FreeBSD automatically promotes large, superpage-aligned allocations.
+ DefaultImageBase = 0x400000;
}
static bool hasBaseReg(uint8_t ModRM) { return (ModRM & 0xc7) != 0x5; }
@@ -152,7 +157,7 @@ RelExpr X86::adjustRelaxExpr(RelType Type, const uint8_t *Data,
}
void X86::writeGotPltHeader(uint8_t *Buf) const {
- write32le(Buf, InX::Dynamic->getVA());
+ write32le(Buf, In.Dynamic->getVA());
}
void X86::writeGotPlt(uint8_t *Buf, const Symbol &S) const {
@@ -183,8 +188,8 @@ void X86::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, V, sizeof(V));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
- uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
return;
@@ -196,7 +201,7 @@ void X86::writePltHeader(uint8_t *Buf) const {
0x90, 0x90, 0x90, 0x90, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint32_t GotPlt = InX::GotPlt->getVA();
+ uint32_t GotPlt = In.GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
@@ -213,7 +218,7 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
if (Config->Pic) {
// jmp *foo@GOT(%ebx)
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
Buf[1] = 0xa3;
write32le(Buf + 2, GotPltEntryAddr - Ebx);
} else {
@@ -447,8 +452,8 @@ void RetpolinePic::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
- uint32_t GotPlt = InX::GotPlt->getVA() - Ebx;
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
+ uint32_t GotPlt = In.GotPlt->getVA() - Ebx;
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 9, GotPlt + 8);
}
@@ -467,7 +472,7 @@ void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize();
+ uint32_t Ebx = In.Got->getVA() + In.Got->getSize();
unsigned Off = getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - Ebx);
write32le(Buf + 8, -Off - 12 + 32);
@@ -506,7 +511,7 @@ void RetpolineNoPic::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint32_t GotPlt = InX::GotPlt->getVA();
+ uint32_t GotPlt = In.GotPlt->getVA();
write32le(Buf + 2, GotPlt + 4);
write32le(Buf + 8, GotPlt + 8);
}
diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp
index d4bdb3730c58..06314155dcc9 100644
--- a/ELF/Arch/X86_64.cpp
+++ b/ELF/Arch/X86_64.cpp
@@ -43,8 +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;
+ bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const override;
private:
void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op,
@@ -55,6 +55,7 @@ private:
template <class ELFT> X86_64<ELFT>::X86_64() {
CopyRel = R_X86_64_COPY;
GotRel = R_X86_64_GLOB_DAT;
+ NoneRel = R_X86_64_NONE;
PltRel = R_X86_64_JUMP_SLOT;
RelativeRel = R_X86_64_RELATIVE;
IRelativeRel = R_X86_64_IRELATIVE;
@@ -66,7 +67,7 @@ template <class ELFT> X86_64<ELFT>::X86_64() {
PltEntrySize = 16;
PltHeaderSize = 16;
TlsGdRelaxSkip = 2;
- TrapInstr = 0xcccccccc; // 0xcc = INT3
+ TrapInstr = {0xcc, 0xcc, 0xcc, 0xcc}; // 0xcc = INT3
// Align to the large page size (known as a superpage or huge page).
// FreeBSD automatically promotes large, superpage-aligned allocations.
@@ -124,7 +125,7 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const {
// required, but it is documented in the psabi and the glibc dynamic linker
// seems to use it (note that this is relevant for linking ld.so, not any
// other program).
- write64le(Buf, InX::Dynamic->getVA());
+ write64le(Buf, In.Dynamic->getVA());
}
template <class ELFT>
@@ -140,8 +141,8 @@ template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const {
0x0f, 0x1f, 0x40, 0x00, // nop
};
memcpy(Buf, PltData, sizeof(PltData));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8
write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16
}
@@ -481,23 +482,27 @@ namespace {
// 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 {
+ uint8_t *End,
+ uint8_t StOther) const {
+ if (Loc + 8 >= End)
+ return false;
+
// 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) {
+ if (memcmp(Loc, "\x64\x48\x3b\x24\x25", 5) == 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);
+ // Adjust "lea X(%rsp),%rYY" to lea "(X - 0x4000)(%rsp),%rYY" where rYY could
+ // be r10 or r11. The lea instruction feeds a subsequent compare which checks
+ // if there is X available stack space. Making X larger effectively reserves
+ // that much additional space. The stack grows downward so subtract the value.
+ if (memcmp(Loc, "\x4c\x8d\x94\x24", 4) == 0 ||
+ memcmp(Loc, "\x4c\x8d\x9c\x24", 4) == 0) {
+ // The offset bytes are encoded four bytes after the start of the
+ // instruction.
+ write32le(Loc + 4, read32le(Loc + 4) - 0x4000);
return true;
}
return false;
@@ -505,7 +510,8 @@ bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
template <>
bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const {
+ uint8_t *End,
+ uint8_t StOther) const {
llvm_unreachable("Target doesn't support split stacks.");
}
@@ -566,8 +572,8 @@ template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const {
};
memcpy(Buf, Insn, sizeof(Insn));
- uint64_t GotPlt = InX::GotPlt->getVA();
- uint64_t Plt = InX::Plt->getVA();
+ uint64_t GotPlt = In.GotPlt->getVA();
+ uint64_t Plt = In.Plt->getVA();
write32le(Buf + 2, GotPlt - Plt - 6 + 8);
write32le(Buf + 9, GotPlt - Plt - 13 + 16);
}
@@ -586,7 +592,7 @@ void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
};
memcpy(Buf, Insn, sizeof(Insn));
- uint64_t Off = TargetInfo::getPltEntryOffset(Index);
+ uint64_t Off = getPltEntryOffset(Index);
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
write32le(Buf + 8, -Off - 12 + 32);
@@ -629,7 +635,7 @@ void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
memcpy(Buf, Insn, sizeof(Insn));
write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7);
- write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12);
+ write32le(Buf + 8, -getPltEntryOffset(Index) - 12);
}
template <class ELFT> static TargetInfo *getTargetInfo() {
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index fb2f53a72025..a1c23b0d49ac 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -15,17 +15,19 @@ add_lld_library(lldELF
Arch/Hexagon.cpp
Arch/Mips.cpp
Arch/MipsArchTree.cpp
+ Arch/MSP430.cpp
Arch/PPC.cpp
Arch/PPC64.cpp
+ Arch/RISCV.cpp
Arch/SPARCV9.cpp
Arch/X86.cpp
Arch/X86_64.cpp
CallGraphSort.cpp
+ DWARF.cpp
Driver.cpp
DriverUtils.cpp
EhFrame.cpp
Filesystem.cpp
- GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
diff --git a/ELF/CallGraphSort.cpp b/ELF/CallGraphSort.cpp
index 33ac159a6e26..2a7d78664b8e 100644
--- a/ELF/CallGraphSort.cpp
+++ b/ELF/CallGraphSort.cpp
@@ -57,10 +57,7 @@ struct Edge {
};
struct Cluster {
- Cluster(int Sec, size_t S) {
- Sections.push_back(Sec);
- Size = S;
- }
+ Cluster(int Sec, size_t S) : Sections{Sec}, Size(S) {}
double getDensity() const {
if (Size == 0)
@@ -72,7 +69,7 @@ struct Cluster {
size_t Size = 0;
uint64_t Weight = 0;
uint64_t InitialWeight = 0;
- std::vector<Edge> Preds;
+ Edge BestPred = {-1, 0};
};
class CallGraphSort {
@@ -96,12 +93,14 @@ constexpr int MAX_DENSITY_DEGRADATION = 8;
constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024;
} // end anonymous namespace
+typedef std::pair<const InputSectionBase *, const InputSectionBase *>
+ SectionPair;
+
// 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;
+ MapVector<SectionPair, uint64_t> &Profile = Config->CallGraphProfile;
DenseMap<const InputSectionBase *, int> SecToCluster;
auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int {
@@ -114,7 +113,7 @@ CallGraphSort::CallGraphSort() {
};
// Create the graph.
- for (const auto &C : Profile) {
+ for (std::pair<SectionPair, uint64_t> &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;
@@ -136,8 +135,12 @@ CallGraphSort::CallGraphSort() {
if (From == To)
continue;
- // Add an edge
- Clusters[To].Preds.push_back({From, Weight});
+ // Remember the best edge.
+ Cluster &ToC = Clusters[To];
+ if (ToC.BestPred.From == -1 || ToC.BestPred.Weight < Weight) {
+ ToC.BestPred.From = From;
+ ToC.BestPred.Weight = Weight;
+ }
}
for (Cluster &C : Clusters)
C.InitialWeight = C.Weight;
@@ -146,9 +149,7 @@ CallGraphSort::CallGraphSort() {
// 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;
+ return NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION;
}
static void mergeClusters(Cluster &Into, Cluster &From) {
@@ -167,9 +168,9 @@ 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];
+ for (size_t I = 0; I < Clusters.size(); ++I) {
+ SortedSecs[I] = I;
+ SecToCluster[I] = &Clusters[I];
}
std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) {
@@ -181,21 +182,11 @@ void CallGraphSort::groupClusters() {
// 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)
+ // Don't consider merging if the edge is unlikely.
+ if (C.BestPred.From == -1 || C.BestPred.Weight * 10 <= C.InitialWeight)
continue;
- Cluster *PredC = SecToCluster[BestPred];
+ Cluster *PredC = SecToCluster[C.BestPred.From];
if (PredC == &C)
continue;
@@ -229,7 +220,7 @@ DenseMap<const InputSectionBase *, int> CallGraphSort::run() {
groupClusters();
// Generate order.
- llvm::DenseMap<const InputSectionBase *, int> OrderMap;
+ DenseMap<const InputSectionBase *, int> OrderMap;
ssize_t CurOrder = 1;
for (const Cluster &C : Clusters)
diff --git a/ELF/Config.h b/ELF/Config.h
index 622324c13e2d..8fb760e592eb 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -47,7 +47,7 @@ enum class ICFLevel { None, Safe, All };
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
-enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll };
+enum class UnresolvedPolicy { ReportError, Warn, Ignore };
// For --orphan-handling.
enum class OrphanHandlingPolicy { Place, Warn, Error };
@@ -127,6 +127,7 @@ struct Configuration {
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
+ bool CallGraphProfileSort;
bool CheckSections;
bool CompressDebugSections;
bool Cref;
@@ -134,11 +135,13 @@ struct Configuration {
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
+ bool EmitLLVM;
bool EmitRelocs;
bool EnableNewDtags;
bool ExecuteOnly;
bool ExportDynamic;
bool FixCortexA53Errata843419;
+ bool FormatBinary = false;
bool GcSections;
bool GdbIndex;
bool GnuHash = false;
@@ -170,19 +173,24 @@ struct Configuration {
bool Trace;
bool ThinLTOEmitImportsFiles;
bool ThinLTOIndexOnly;
+ bool TocOptimize;
bool UndefinedVersion;
bool UseAndroidRelrTags = false;
bool WarnBackrefs;
bool WarnCommon;
+ bool WarnIfuncTextrel;
bool WarnMissingEntry;
bool WarnSymbolOrdering;
bool WriteAddends;
bool ZCombreloc;
bool ZCopyreloc;
bool ZExecstack;
+ bool ZGlobal;
bool ZHazardplt;
bool ZInitfirst;
+ bool ZInterpose;
bool ZKeepTextSectionPrefix;
+ bool ZNodefaultlib;
bool ZNodelete;
bool ZNodlopen;
bool ZNow;
@@ -212,6 +220,7 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
+ int32_t SplitStackAdjustSize;
// The following config options do not directly correspond to any
// particualr command line options.
diff --git a/ELF/GdbIndex.cpp b/ELF/DWARF.cpp
index 85449a200647..17e1a4d600eb 100644
--- a/ELF/GdbIndex.cpp
+++ b/ELF/DWARF.cpp
@@ -1,4 +1,4 @@
-//===- GdbIndex.cpp -------------------------------------------------------===//
+//===- DWARF.cpp ----------------------------------------------------------===//
//
// The LLVM Linker
//
@@ -14,8 +14,9 @@
//
//===----------------------------------------------------------------------===//
-#include "GdbIndex.h"
+#include "DWARF.h"
#include "Symbols.h"
+#include "Target.h"
#include "lld/Common/Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
@@ -29,24 +30,28 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) {
for (InputSectionBase *Sec : Obj->getSections()) {
if (!Sec)
continue;
- if (LLDDWARFSection *M = StringSwitch<LLDDWARFSection *>(Sec->Name)
- .Case(".debug_info", &InfoSection)
- .Case(".debug_ranges", &RangeSection)
- .Case(".debug_line", &LineSection)
- .Default(nullptr)) {
- Sec->maybeDecompress();
- M->Data = toStringRef(Sec->Data);
+
+ if (LLDDWARFSection *M =
+ StringSwitch<LLDDWARFSection *>(Sec->Name)
+ .Case(".debug_addr", &AddrSection)
+ .Case(".debug_gnu_pubnames", &GnuPubNamesSection)
+ .Case(".debug_gnu_pubtypes", &GnuPubTypesSection)
+ .Case(".debug_info", &InfoSection)
+ .Case(".debug_ranges", &RangeSection)
+ .Case(".debug_rnglists", &RngListsSection)
+ .Case(".debug_line", &LineSection)
+ .Default(nullptr)) {
+ M->Data = toStringRef(Sec->data());
M->Sec = Sec;
continue;
}
+
if (Sec->Name == ".debug_abbrev")
- AbbrevSection = toStringRef(Sec->Data);
- else if (Sec->Name == ".debug_gnu_pubnames")
- GnuPubNamesSection = toStringRef(Sec->Data);
- else if (Sec->Name == ".debug_gnu_pubtypes")
- GnuPubTypesSection = toStringRef(Sec->Data);
+ AbbrevSection = toStringRef(Sec->data());
else if (Sec->Name == ".debug_str")
- StrSection = toStringRef(Sec->Data);
+ StrSection = toStringRef(Sec->data());
+ else if (Sec->Name == ".debug_line_str")
+ LineStringSection = toStringRef(Sec->data());
}
}
@@ -73,7 +78,10 @@ LLDDwarfObj<ELFT>::findAux(const InputSectionBase &Sec, uint64_t Pos,
// Broken debug info can point to a non-Defined symbol.
auto *DR = dyn_cast<Defined>(&File->getRelocTargetSym(Rel));
if (!DR) {
- error("unsupported relocation target while parsing debug info");
+ RelType Type = Rel.getType(Config->IsMips64EL);
+ if (Type != Target->NoneRel)
+ error(toString(File) + ": relocation " + lld::toString(Type) + " at 0x" +
+ llvm::utohexstr(Rel.r_offset) + " has unsupported target");
return None;
}
uint64_t Val = DR->Value + getAddend<ELFT>(Rel);
diff --git a/ELF/GdbIndex.h b/ELF/DWARF.h
index eba1ba22f879..8ecf02c77fb4 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/DWARF.h
@@ -1,4 +1,4 @@
-//===- GdbIndex.h --------------------------------------------*- C++ -*-===//
+//===- DWARF.h -----------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
@@ -7,10 +7,11 @@
//
//===-------------------------------------------------------------------===//
-#ifndef LLD_ELF_GDB_INDEX_H
-#define LLD_ELF_GDB_INDEX_H
+#ifndef LLD_ELF_DWARF_H
+#define LLD_ELF_DWARF_H
#include "InputFiles.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ELF.h"
@@ -24,44 +25,66 @@ struct LLDDWARFSection final : public llvm::DWARFSection {
};
template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
- LLDDWARFSection InfoSection;
- LLDDWARFSection RangeSection;
- LLDDWARFSection LineSection;
- StringRef AbbrevSection;
- StringRef GnuPubNamesSection;
- StringRef GnuPubTypesSection;
- StringRef StrSection;
-
- template <class RelTy>
- llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec,
- uint64_t Pos,
- ArrayRef<RelTy> Rels) const;
-
public:
explicit LLDDwarfObj(ObjFile<ELFT> *Obj);
- const llvm::DWARFSection &getInfoSection() const override {
- return InfoSection;
+
+ void forEachInfoSections(
+ llvm::function_ref<void(const llvm::DWARFSection &)> F) const override {
+ F(InfoSection);
}
+
const llvm::DWARFSection &getRangeSection() const override {
return RangeSection;
}
+
+ const llvm::DWARFSection &getRnglistsSection() const override {
+ return RngListsSection;
+ }
+
const llvm::DWARFSection &getLineSection() const override {
return LineSection;
}
- StringRef getFileName() const override { return ""; }
- StringRef getAbbrevSection() const override { return AbbrevSection; }
- StringRef getStringSection() const override { return StrSection; }
- StringRef getGnuPubNamesSection() const override {
+
+ const llvm::DWARFSection &getAddrSection() const override {
+ return AddrSection;
+ }
+
+ const llvm::DWARFSection &getGnuPubNamesSection() const override {
return GnuPubNamesSection;
}
- StringRef getGnuPubTypesSection() const override {
+
+ const llvm::DWARFSection &getGnuPubTypesSection() const override {
return GnuPubTypesSection;
}
+
+ StringRef getFileName() const override { return ""; }
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ StringRef getStringSection() const override { return StrSection; }
+ StringRef getLineStringSection() const override { return LineStringSection; }
+
bool isLittleEndian() const override {
return ELFT::TargetEndianness == llvm::support::little;
}
+
llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec,
uint64_t Pos) const override;
+
+private:
+ template <class RelTy>
+ llvm::Optional<llvm::RelocAddrEntry> findAux(const InputSectionBase &Sec,
+ uint64_t Pos,
+ ArrayRef<RelTy> Rels) const;
+
+ LLDDWARFSection GnuPubNamesSection;
+ LLDDWARFSection GnuPubTypesSection;
+ LLDDWARFSection InfoSection;
+ LLDDWARFSection RangeSection;
+ LLDDWARFSection RngListsSection;
+ LLDDWARFSection LineSection;
+ LLDDWARFSection AddrSection;
+ StringRef AbbrevSection;
+ StringRef StrSection;
+ StringRef LineStringSection;
};
} // namespace elf
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 693dba64ab5a..13b6119e2dc9 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -63,6 +63,7 @@ using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::sys;
+using namespace llvm::support;
using namespace lld;
using namespace lld::elf;
@@ -74,7 +75,7 @@ static void setConfigs(opt::InputArgList &Args);
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = sys::path::filename(Args[0]);
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
@@ -84,7 +85,6 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
InputSections.clear();
OutputSections.clear();
- Tar = nullptr;
BinaryFiles.clear();
BitcodeFiles.clear();
ObjectFiles.clear();
@@ -94,6 +94,10 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
Driver = make<LinkerDriver>();
Script = make<LinkerScript>();
Symtab = make<SymbolTable>();
+
+ Tar = nullptr;
+ memset(&In, 0, sizeof(In));
+
Config->ProgName = Args[0];
Driver->main(Args);
@@ -125,9 +129,11 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
.Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
.Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Case("elf32lriscv", {ELF32LEKind, EM_RISCV})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
+ .Case("elf64lriscv", {ELF64LEKind, EM_RISCV})
.Case("elf64ppc", {ELF64BEKind, EM_PPC64})
.Case("elf64lppc", {ELF64LEKind, EM_PPC64})
.Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64})
@@ -183,7 +189,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
return;
MemoryBufferRef MBRef = *Buffer;
- if (InBinary) {
+ if (Config->FormatBinary) {
Files.push_back(make<BinaryFile>(MBRef));
return;
}
@@ -218,7 +224,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
return;
}
case file_magic::elf_shared_object:
- if (Config->Relocatable) {
+ if (Config->Static || Config->Relocatable) {
error("attempted static link of dynamic object " + Path);
return;
}
@@ -269,14 +275,17 @@ static void initLLVM() {
// Some command line options or some combinations of them are not allowed.
// This function checks for such errors.
-static void checkOptions(opt::InputArgList &Args) {
+static void checkOptions() {
// The MIPS ABI as of 2016 does not support the GNU-style symbol lookup
// table which is a relatively new feature.
if (Config->EMachine == EM_MIPS && Config->GnuHash)
- error("the .gnu.hash section is not compatible with the MIPS target.");
+ error("the .gnu.hash section is not compatible with the MIPS target");
if (Config->FixCortexA53Errata843419 && Config->EMachine != EM_AARCH64)
- error("--fix-cortex-a53-843419 is only supported on AArch64 targets.");
+ error("--fix-cortex-a53-843419 is only supported on AArch64 targets");
+
+ if (Config->TocOptimize && Config->EMachine != EM_PPC64)
+ error("--toc-optimize is only supported on the PowerPC64 target");
if (Config->Pie && Config->Shared)
error("-shared and -pie may not be used together");
@@ -336,12 +345,13 @@ static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2,
return Default;
}
-static bool isKnown(StringRef S) {
+static bool isKnownZFlag(StringRef S) {
return S == "combreloc" || S == "copyreloc" || S == "defs" ||
- S == "execstack" || S == "hazardplt" || S == "initfirst" ||
+ S == "execstack" || S == "global" || S == "hazardplt" ||
+ S == "initfirst" || S == "interpose" ||
S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
- S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" ||
- S == "nodlopen" || S == "noexecstack" ||
+ S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" ||
+ 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" ||
@@ -351,7 +361,7 @@ static bool isKnown(StringRef S) {
// 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()))
+ if (!isKnownZFlag(Arg->getValue()))
error("unknown -z value: " + StringRef(Arg->getValue()));
}
@@ -386,31 +396,30 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
message(getLLDVersion() + " (compatible with GNU linkers)");
- // The behavior of -v or --version is a bit strange, but this is
- // needed for compatibility with GNU linkers.
- if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT))
- return;
- if (Args.hasArg(OPT_version))
- return;
-
if (const char *Path = getReproduceOption(Args)) {
// Note that --reproduce is a debug option so you can ignore it
// if you are trying to understand the whole picture of the code.
Expected<std::unique_ptr<TarWriter>> ErrOrWriter =
TarWriter::create(Path, path::stem(Path));
if (ErrOrWriter) {
- Tar = ErrOrWriter->get();
+ Tar = std::move(*ErrOrWriter);
Tar->append("response.txt", createResponseFile(Args));
Tar->append("version.txt", getLLDVersion() + "\n");
- make<std::unique_ptr<TarWriter>>(std::move(*ErrOrWriter));
} else {
- error(Twine("--reproduce: failed to open ") + Path + ": " +
- toString(ErrOrWriter.takeError()));
+ error("--reproduce: " + toString(ErrOrWriter.takeError()));
}
}
readConfigs(Args);
checkZOptions(Args);
+
+ // The behavior of -v or --version is a bit strange, but this is
+ // needed for compatibility with GNU linkers.
+ if (Args.hasArg(OPT_v) && !Args.hasArg(OPT_INPUT))
+ return;
+ if (Args.hasArg(OPT_version))
+ return;
+
initLLVM();
createFiles(Args);
if (errorCount())
@@ -418,7 +427,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) {
inferMachineType();
setConfigs(Args);
- checkOptions(Args);
+ checkOptions();
if (errorCount())
return;
@@ -448,9 +457,6 @@ static std::string getRpath(opt::InputArgList &Args) {
// Determines what we should do if there are remaining unresolved
// symbols after the name resolution.
static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
- if (Args.hasArg(OPT_relocatable))
- return UnresolvedPolicy::IgnoreAll;
-
UnresolvedPolicy ErrorOrWarn = Args.hasFlag(OPT_error_unresolved_symbols,
OPT_warn_unresolved_symbols, true)
? UnresolvedPolicy::ReportError
@@ -497,14 +503,11 @@ static Target2Policy getTarget2(opt::InputArgList &Args) {
}
static bool isOutputFormatBinary(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_oformat)) {
- StringRef S = Arg->getValue();
- if (S == "binary")
- return true;
- if (S.startswith("elf"))
- return false;
+ StringRef S = Args.getLastArgValue(OPT_oformat, "elf");
+ if (S == "binary")
+ return true;
+ if (!S.startswith("elf"))
error("unknown --oformat value: " + S);
- }
return false;
}
@@ -645,38 +648,56 @@ static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) {
static void readCallGraph(MemoryBufferRef MB) {
// Build a map from symbol name to section
- DenseMap<StringRef, const Symbol *> SymbolNameToSymbol;
+ DenseMap<StringRef, Symbol *> Map;
for (InputFile *File : ObjectFiles)
for (Symbol *Sym : File->getSymbols())
- SymbolNameToSymbol[Sym->getName()] = Sym;
+ Map[Sym->getName()] = Sym;
+
+ auto FindSection = [&](StringRef Name) -> InputSectionBase * {
+ Symbol *Sym = Map.lookup(Name);
+ if (!Sym) {
+ if (Config->WarnSymbolOrdering)
+ warn(MB.getBufferIdentifier() + ": no such symbol: " + Name);
+ return nullptr;
+ }
+ maybeWarnUnorderableSymbol(Sym);
+
+ if (Defined *DR = dyn_cast_or_null<Defined>(Sym))
+ return dyn_cast_or_null<InputSectionBase>(DR->Section);
+ return nullptr;
+ };
- for (StringRef L : args::getLines(MB)) {
+ for (StringRef Line : args::getLines(MB)) {
SmallVector<StringRef, 3> Fields;
- L.split(Fields, ' ');
+ Line.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 (Fields.size() != 3 || !to_integer(Fields[2], Count)) {
+ error(MB.getBufferIdentifier() + ": parse error");
+ return;
+ }
+
+ if (InputSectionBase *From = FindSection(Fields[0]))
+ if (InputSectionBase *To = FindSection(Fields[1]))
+ Config->CallGraphProfile[std::make_pair(From, To)] += Count;
+ }
+}
+
+template <class ELFT> static void readCallGraphsFromObjectFiles() {
+ for (auto File : ObjectFiles) {
+ auto *Obj = cast<ObjFile<ELFT>>(File);
+
+ for (const Elf_CGProfile_Impl<ELFT> &CGPE : Obj->CGProfile) {
+ auto *FromSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_from));
+ auto *ToSym = dyn_cast<Defined>(&Obj->getSymbol(CGPE.cgp_to));
+ if (!FromSym || !ToSym)
+ continue;
+
+ auto *From = dyn_cast_or_null<InputSectionBase>(FromSym->Section);
+ auto *To = dyn_cast_or_null<InputSectionBase>(ToSym->Section);
+ if (From && To)
+ Config->CallGraphProfile[{From, To}] += CGPE.cgp_weight;
}
- 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;
}
}
@@ -753,7 +774,10 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr =
Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false);
+ Config->EmitLLVM = Args.hasArg(OPT_plugin_opt_emit_llvm, false);
Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+ Config->CallGraphProfileSort = Args.hasFlag(
+ OPT_call_graph_profile_sort, OPT_no_call_graph_profile_sort, true);
Config->EnableNewDtags =
Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
Config->Entry = Args.getLastArgValue(OPT_entry);
@@ -808,6 +832,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
Config->SoName = Args.getLastArgValue(OPT_soname);
Config->SortSection = getSortSection(Args);
+ Config->SplitStackAdjustSize = args::getInteger(Args, OPT_split_stack_adjust_size, 16384);
Config->Strip = getStrip(Args);
Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
Config->Target1Rel = Args.hasFlag(OPT_target1_rel, OPT_target1_abs, false);
@@ -837,15 +862,20 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
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->WarnIfuncTextrel =
+ Args.hasFlag(OPT_warn_ifunc_textrel, OPT_no_warn_ifunc_textrel, 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->ZGlobal = hasZOption(Args, "global");
Config->ZHazardplt = hasZOption(Args, "hazardplt");
Config->ZInitfirst = hasZOption(Args, "initfirst");
+ Config->ZInterpose = hasZOption(Args, "interpose");
Config->ZKeepTextSectionPrefix = getZFlag(
Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false);
+ Config->ZNodefaultlib = hasZOption(Args, "nodefaultlib");
Config->ZNodelete = hasZOption(Args, "nodelete");
Config->ZNodlopen = hasZOption(Args, "nodlopen");
Config->ZNow = getZFlag(Args, "now", "lazy", false);
@@ -876,6 +906,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
+ if (Config->SplitStackAdjustSize < 0)
+ error("--split-stack-adjust-size: size must be >= 0");
+
// Parse ELF{32,64}{LE,BE} and CPU type.
if (auto *Arg = Args.getLastArg(OPT_m)) {
StringRef S = Arg->getValue();
@@ -964,22 +997,17 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
// This function initialize such members. See Config.h for the details
// of these values.
static void setConfigs(opt::InputArgList &Args) {
- ELFKind Kind = Config->EKind;
- uint16_t Machine = Config->EMachine;
+ ELFKind K = Config->EKind;
+ uint16_t M = Config->EMachine;
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->Is64 = (K == ELF64LEKind || K == ELF64BEKind);
+ Config->IsLE = (K == ELF32LEKind || K == ELF64LEKind);
+ Config->Endianness = Config->IsLE ? endianness::little : endianness::big;
+ Config->IsMips64EL = (K == ELF64LEKind && M == EM_MIPS);
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.
@@ -993,8 +1021,9 @@ static void setConfigs(opt::InputArgList &Args) {
// 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;
+ Config->IsRela = M == EM_AARCH64 || M == EM_AMDGPU || M == EM_HEXAGON ||
+ M == EM_PPC || M == EM_PPC64 || M == EM_RISCV ||
+ M == EM_X86_64;
// If the output uses REL relocations we must store the dynamic relocation
// addends to the output sections. We also store addends for RELA relocations
@@ -1004,10 +1033,13 @@ static void setConfigs(opt::InputArgList &Args) {
Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs,
OPT_no_apply_dynamic_relocs, false) ||
!Config->IsRela;
+
+ Config->TocOptimize =
+ Args.hasFlag(OPT_toc_optimize, OPT_no_toc_optimize, M == EM_PPC64);
}
// Returns a value of "-format" option.
-static bool getBinaryOption(StringRef S) {
+static bool isFormatBinary(StringRef S) {
if (S == "binary")
return true;
if (S == "elf" || S == "default")
@@ -1034,7 +1066,10 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
StringRef From;
StringRef To;
std::tie(From, To) = StringRef(Arg->getValue()).split('=');
- readDefsym(From, MemoryBufferRef(To, "-defsym"));
+ if (From.empty() || To.empty())
+ error("-defsym: syntax error: " + StringRef(Arg->getValue()));
+ else
+ readDefsym(From, MemoryBufferRef(To, "-defsym"));
break;
}
case OPT_script:
@@ -1049,7 +1084,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
Config->AsNeeded = true;
break;
case OPT_format:
- InBinary = getBinaryOption(Arg->getValue());
+ Config->FormatBinary = isFormatBinary(Arg->getValue());
break;
case OPT_no_as_needed:
Config->AsNeeded = false;
@@ -1220,33 +1255,34 @@ template <class ELFT> static void handleUndefined(StringRef Name) {
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;
+template <class ELFT> static void handleLibcall(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym || !Sym->isLazy())
+ return;
+
+ MemoryBufferRef MB;
+ if (auto *LO = dyn_cast<LazyObject>(Sym))
+ MB = LO->File->MB;
+ else
+ MB = cast<LazyArchive>(Sym)->getMemberBuffer();
+
+ if (isBitcode(MB))
+ Symtab->fetchLazy<ELFT>(Sym);
}
-// 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() {
+// 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.
+template <class ELFT> static void demoteSharedSymbols() {
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;
+ if (auto *S = dyn_cast<SharedSymbol>(Sym)) {
+ if (!S->getFile<ELFT>().IsNeeded) {
+ bool Used = S->Used;
+ replaceSymbol<Undefined>(S, nullptr, S->getName(), STB_WEAK, S->StOther,
+ S->Type);
+ S->Used = Used;
+ }
}
}
}
@@ -1315,6 +1351,85 @@ static void findKeepUniqueSections(opt::InputArgList &Args) {
}
}
+template <class ELFT> static Symbol *addUndefined(StringRef Name) {
+ return Symtab->addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, 0, false,
+ nullptr);
+}
+
+// The --wrap option is a feature to rename symbols so that you can write
+// wrappers for existing functions. If you pass `-wrap=foo`, all
+// occurrences of symbol `foo` are resolved to `wrap_foo` (so, you are
+// expected to write `wrap_foo` function as a wrapper). The original
+// symbol becomes accessible as `real_foo`, so you can call that from your
+// wrapper.
+//
+// This data structure is instantiated for each -wrap option.
+struct WrappedSymbol {
+ Symbol *Sym;
+ Symbol *Real;
+ Symbol *Wrap;
+};
+
+// Handles -wrap option.
+//
+// This function instantiates wrapper symbols. At this point, they seem
+// like they are not being used at all, so we explicitly set some flags so
+// that LTO won't eliminate them.
+template <class ELFT>
+static std::vector<WrappedSymbol> addWrappedSymbols(opt::InputArgList &Args) {
+ std::vector<WrappedSymbol> V;
+ DenseSet<StringRef> Seen;
+
+ for (auto *Arg : Args.filtered(OPT_wrap)) {
+ StringRef Name = Arg->getValue();
+ if (!Seen.insert(Name).second)
+ continue;
+
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ continue;
+
+ Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
+ Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
+ V.push_back({Sym, Real, Wrap});
+
+ // We want to tell LTO not to inline symbols to be overwritten
+ // because LTO doesn't know the final symbol contents after renaming.
+ Real->CanInline = false;
+ Sym->CanInline = false;
+
+ // Tell LTO not to eliminate these symbols.
+ Sym->IsUsedInRegularObj = true;
+ Wrap->IsUsedInRegularObj = true;
+ }
+ return V;
+}
+
+// Do renaming for -wrap by updating pointers to symbols.
+//
+// When this function is executed, only InputFiles and symbol table
+// contain pointers to symbol objects. We visit them to replace pointers,
+// so that wrapped symbols are swapped as instructed by the command line.
+template <class ELFT> static void wrapSymbols(ArrayRef<WrappedSymbol> Wrapped) {
+ DenseMap<Symbol *, Symbol *> Map;
+ for (const WrappedSymbol &W : Wrapped) {
+ Map[W.Sym] = W.Wrap;
+ Map[W.Real] = W.Sym;
+ }
+
+ // Update pointers in input files.
+ parallelForEach(ObjectFiles, [&](InputFile *File) {
+ std::vector<Symbol *> &Syms = File->getMutableSymbols();
+ for (size_t I = 0, E = Syms.size(); I != E; ++I)
+ if (Symbol *S = Map.lookup(Syms[I]))
+ Syms[I] = S;
+ });
+
+ // Update pointers in the symbol table.
+ for (const WrappedSymbol &W : Wrapped)
+ Symtab->wrap(W.Sym, W.Real, W.Wrap);
+}
+
static const char *LibcallRoutineNames[] = {
#define HANDLE_LIBCALL(code, name) name,
#include "llvm/IR/RuntimeLibcalls.def"
@@ -1325,6 +1440,8 @@ static const char *LibcallRoutineNames[] = {
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Target = getTarget();
+ InX<ELFT>::VerSym = nullptr;
+ InX<ELFT>::VerNeed = nullptr;
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -1380,8 +1497,8 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Some symbols (such as __ehdr_start) are defined lazily only when there
// are undefined symbols for them, so we add these to trigger that logic.
- for (StringRef Sym : Script->ReferencedSymbols)
- Symtab->addUndefined<ELFT>(Sym);
+ for (StringRef Name : Script->ReferencedSymbols)
+ addUndefined<ELFT>(Name);
// Handle the `--undefined <sym>` options.
for (StringRef S : Config->Undefined)
@@ -1396,11 +1513,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// in a bitcode file in an archive member, we need to arrange to use LTO to
// compile those archive members by adding them to the link beforehand.
//
- // With this the symbol table should be complete. After this, no new names
- // except a few linker-synthesized ones will be added to the symbol table.
+ // However, adding all libcall symbols to the link can have undesired
+ // consequences. For example, the libgcc implementation of
+ // __sync_val_compare_and_swap_8 on 32-bit ARM pulls in an .init_array entry
+ // that aborts the program if the Linux kernel does not support 64-bit
+ // atomics, which would prevent the program from running even if it does not
+ // use 64-bit atomics.
+ //
+ // Therefore, we only add libcall symbols to the link before LTO if we have
+ // to, i.e. if the symbol's definition is in bitcode. Any other required
+ // libcall symbols will be added to the link after LTO when we add the LTO
+ // object file to the link.
if (!BitcodeFiles.empty())
for (const char *S : LibcallRoutineNames)
- handleUndefined<ELFT>(S);
+ handleLibcall<ELFT>(S);
// Return if there were name resolution errors.
if (errorCount())
@@ -1424,6 +1550,9 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
Out::ElfHeader = make<OutputSection>("", 0, SHF_ALLOC);
Out::ElfHeader->Size = sizeof(typename ELFT::Ehdr);
+ // Create wrapped symbols for -wrap option.
+ std::vector<WrappedSymbol> Wrapped = addWrappedSymbols<ELFT>(Args);
+
// We need to create some reserved symbols such as _end. Create them.
if (!Config->Relocatable)
addReservedSymbols();
@@ -1436,12 +1565,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
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.
+ //
+ // With this the symbol table should be complete. After this, no new names
+ // except a few linker-synthesized ones will be added to the symbol table.
Symtab->addCombinedLTOObject<ELFT>();
if (errorCount())
return;
@@ -1452,8 +1580,15 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->ThinLTOIndexOnly)
return;
+ // Likewise, --plugin-opt=emit-llvm is an option to make LTO create
+ // an output file in bitcode and exit, so that you can just get a
+ // combined bitcode file.
+ if (Config->EmitLLVM)
+ return;
+
// Apply symbol renames for -wrap.
- Symtab->applySymbolWrap();
+ if (!Wrapped.empty())
+ wrapSymbols<ELFT>(Wrapped);
// Now that we have a complete list of input files.
// Beyond this point, no new files are added.
@@ -1481,27 +1616,19 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// supports them.
if (Config->ARMHasBlx == false)
warn("lld uses blx instruction, no object with architecture supporting "
- "feature detected.");
- if (Config->ARMJ1J2BranchEncoding == false)
- warn("lld uses extended branch encoding, no object with architecture "
- "supporting feature detected.");
- if (Config->ARMHasMovtMovw == false)
- warn("lld may use movt/movw, no object with architecture supporting "
- "feature detected.");
+ "feature detected");
}
// This adds a .comment section containing a version string. We have to add it
- // before decompressAndMergeSections because the .comment section is a
- // mergeable section.
+ // before mergeSections because the .comment section is a mergeable section.
if (!Config->Relocatable)
InputSections.push_back(createCommentSection());
// Do size optimizations: garbage collection, merging of SHF_MERGE sections
// and identical code folding.
- decompressSections();
splitSections<ELFT>();
markLive<ELFT>();
- demoteSymbols<ELFT>();
+ demoteSharedSymbols<ELFT>();
mergeSections();
if (Config->ICF != ICFLevel::None) {
findKeepUniqueSections<ELFT>(Args);
@@ -1509,9 +1636,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
}
// 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);
+ if (Config->CallGraphProfileSort) {
+ if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file))
+ if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
+ readCallGraph(*Buffer);
+ readCallGraphsFromObjectFiles<ELFT>();
+ }
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 99e194d9b66c..81d7f608e588 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -42,9 +42,6 @@ private:
// True if we are in --start-lib and --end-lib.
bool InLib = false;
- // True if we are in -format=binary and -format=elf.
- bool InBinary = false;
-
std::vector<InputFile *> Files;
};
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 698e06edfe63..e51d02e38da1 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -139,8 +139,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
}
void elf::printHelp() {
- ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld",
- false /*ShowHidden*/, true /*ShowAllAliases*/);
+ ELFOptTable().PrintHelp(
+ outs(), (Config->ProgName + " [options] file...").str().c_str(), "lld",
+ false /*ShowHidden*/, true /*ShowAllAliases*/);
outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 20b32c0a96e6..95d444bdc2a1 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -44,7 +44,7 @@ public:
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
- IS->getObjMsg((const uint8_t *)Loc - IS->Data.data()));
+ IS->getObjMsg((const uint8_t *)Loc - IS->data().data()));
}
uint8_t readByte();
@@ -59,7 +59,7 @@ private:
}
size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
- return EhReader(S, S->Data.slice(Off)).readEhRecordSize();
+ return EhReader(S, S->data().slice(Off)).readEhRecordSize();
}
// .eh_frame section is a sequence of records. Each record starts with
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 075938bd16b9..e917ae76a689 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -252,7 +252,10 @@ bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
auto *DA = dyn_cast<Defined>(&SA);
auto *DB = dyn_cast<Defined>(&SB);
- if (!DA || !DB)
+
+ // Placeholder symbols generated by linker scripts look the same now but
+ // may have different values later.
+ if (!DA || !DB || DA->ScriptDefined || DB->ScriptDefined)
return false;
// Relocations referring to absolute symbols are constant-equal if their
@@ -298,7 +301,7 @@ bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA,
template <class ELFT>
bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) {
if (A->NumRelocations != B->NumRelocations || A->Flags != B->Flags ||
- A->getSize() != B->getSize() || A->Data != B->Data)
+ A->getSize() != B->getSize() || A->data() != B->data())
return false;
// If two sections have different output sections, we cannot merge them.
@@ -420,6 +423,21 @@ void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) {
++Cnt;
}
+// Combine the hashes of the sections referenced by the given section into its
+// hash.
+template <class ELFT, class RelTy>
+static void combineRelocHashes(InputSection *IS, ArrayRef<RelTy> Rels) {
+ uint32_t Hash = IS->Class[1];
+ for (RelTy Rel : Rels) {
+ Symbol &S = IS->template getFile<ELFT>()->getRelocTargetSym(Rel);
+ if (auto *D = dyn_cast<Defined>(&S))
+ if (auto *RelSec = dyn_cast_or_null<InputSection>(D->Section))
+ Hash ^= RelSec->Class[1];
+ }
+ // Set MSB to 1 to avoid collisions with non-hash IDs.
+ IS->Class[0] = Hash | (1U << 31);
+}
+
static void print(const Twine &S) {
if (Config->PrintIcfSections)
message(S);
@@ -435,8 +453,14 @@ 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] = xxHash64(S->Data) | (1U << 31);
+ S->Class[1] = xxHash64(S->data());
+ });
+
+ parallelForEach(Sections, [&](InputSection *S) {
+ if (S->AreRelocsRela)
+ combineRelocHashes<ELFT>(S, S->template relas<ELFT>());
+ else
+ combineRelocHashes<ELFT>(S, S->template rels<ELFT>());
});
// From now on, sections in Sections vector are ordered so that sections
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 0eb605a556ae..e4d1dec7cbcb 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -46,7 +46,7 @@ std::vector<LazyObjFile *> elf::LazyObjFiles;
std::vector<InputFile *> elf::ObjectFiles;
std::vector<InputFile *> elf::SharedFiles;
-TarWriter *elf::Tar;
+std::unique_ptr<TarWriter> elf::Tar;
InputFile::InputFile(Kind K, MemoryBufferRef M)
: MB(M), GroupId(NextGroupId), FileKind(K) {
@@ -125,11 +125,7 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec,
template <class ELFT> void ObjFile<ELFT>::initializeDwarf() {
Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this));
- const DWARFObject &Obj = Dwarf->getDWARFObj();
- DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE,
- Config->Wordsize);
-
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) {
+ for (std::unique_ptr<DWARFUnit> &CU : Dwarf->compile_units()) {
auto Report = [](Error Err) {
handleAllErrors(std::move(Err),
[](ErrorInfoBase &Info) { warn(Info.message()); });
@@ -416,6 +412,11 @@ void ObjFile<ELFT>::initializeSections(
continue;
const Elf_Shdr &Sec = ObjSections[I];
+ if (Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
+ CGProfile = check(
+ this->getObj().template getSectionContentsAsArray<Elf_CGProfile>(
+ &Sec));
+
// SHF_EXCLUDE'ed sections are discarded by the linker. However,
// if -r is given, we'll let the final link discard such sections.
// This is compatible with GNU.
@@ -442,6 +443,10 @@ void ObjFile<ELFT>::initializeSections(
bool IsNew = ComdatGroups.insert(CachedHashStringRef(Signature)).second;
this->Sections[I] = &InputSection::Discarded;
+ // We only support GRP_COMDAT type of group. Get the all entries of the
+ // section here to let getShtGroupEntries to check the type early for us.
+ ArrayRef<Elf_Word> Entries = getShtGroupEntries(Sec);
+
// If it is a new section group, we want to keep group members.
// Group leader sections, which contain indices of group members, are
// discarded because they are useless beyond this point. The only
@@ -454,7 +459,7 @@ void ObjFile<ELFT>::initializeSections(
}
// Otherwise, discard group members.
- for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
+ for (uint32_t SecIndex : Entries) {
if (SecIndex >= Size)
fatal(toString(this) +
": invalid section index in group: " + Twine(SecIndex));
@@ -478,11 +483,13 @@ void ObjFile<ELFT>::initializeSections(
// .ARM.exidx sections have a reverse dependency on the InputSection they
// have a SHF_LINK_ORDER dependency, this is identified by the sh_link.
if (Sec.sh_flags & SHF_LINK_ORDER) {
- if (Sec.sh_link >= this->Sections.size())
+ InputSectionBase *LinkSec = nullptr;
+ if (Sec.sh_link < this->Sections.size())
+ LinkSec = this->Sections[Sec.sh_link];
+ if (!LinkSec)
fatal(toString(this) +
": invalid sh_link index: " + Twine(Sec.sh_link));
- InputSectionBase *LinkSec = this->Sections[Sec.sh_link];
InputSection *IS = cast<InputSection>(this->Sections[I]);
LinkSec->DependentSections.push_back(IS);
if (!isa<InputSection>(LinkSec))
@@ -598,7 +605,7 @@ InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
// as a given section.
static InputSection *toRegularSection(MergeInputSection *Sec) {
return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment,
- Sec->Data, Sec->Name);
+ Sec->data(), Sec->Name);
}
template <class ELFT>
@@ -618,9 +625,9 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// FIXME: Retain the first attribute section we see. The eglibc ARM
// dynamic loaders require the presence of an attribute section for dlopen
// to work. In a full implementation we would merge all attribute sections.
- if (InX::ARMAttributes == nullptr) {
- InX::ARMAttributes = make<InputSection>(*this, Sec, Name);
- return InX::ARMAttributes;
+ if (In.ARMAttributes == nullptr) {
+ In.ARMAttributes = make<InputSection>(*this, Sec, Name);
+ return In.ARMAttributes;
}
return &InputSection::Discarded;
}
@@ -638,8 +645,16 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// This section contains relocation information.
// If -r is given, we do not interpret or apply relocation
// but just copy relocation sections to output.
- if (Config->Relocatable)
- return make<InputSection>(*this, Sec, Name);
+ if (Config->Relocatable) {
+ InputSection *RelocSec = make<InputSection>(*this, Sec, Name);
+ // We want to add a dependency to target, similar like we do for
+ // -emit-relocs below. This is useful for the case when linker script
+ // contains the "/DISCARD/". It is perhaps uncommon to use a script with
+ // -r, but we faced it in the Linux kernel and have to handle such case
+ // and not to crash.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
if (Target->FirstRelocation)
fatal(toString(this) +
@@ -704,7 +719,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
// for split stack will include a .note.GNU-split-stack section.
if (Name == ".note.GNU-split-stack") {
if (Config->Relocatable) {
- error("Cannot mix split-stack and non-split-stack in a relocatable link");
+ error("cannot mix split-stack and non-split-stack in a relocatable link");
return &InputSection::Discarded;
}
this->SplitStack = true;
@@ -806,7 +821,7 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) {
if (Sec == &InputSection::Discarded)
return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type,
/*CanOmitFromDynSym=*/false, this);
- return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec,
+ return Symtab->addDefined(Name, StOther, Type, Value, Size, Binding, Sec,
this);
}
}
@@ -940,8 +955,7 @@ std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() {
auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef);
Verdef += CurVerdef->vd_next;
unsigned VerdefIndex = CurVerdef->vd_ndx;
- if (Verdefs.size() <= VerdefIndex)
- Verdefs.resize(VerdefIndex + 1);
+ Verdefs.resize(VerdefIndex + 1);
Verdefs[VerdefIndex] = CurVerdef;
}
@@ -993,25 +1007,25 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
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()) {
- 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.
+ StringRef Name = CHECK(Sym.getName(this->StringTable), this);
if (Sym.getBinding() == STB_LOCAL) {
warn("found local symbol '" + Name +
"' in global part of symbol table in file " + toString(this));
continue;
}
+ if (Sym.isUndefined()) {
+ Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType(),
+ /*CanOmitFromDynSym=*/false, this);
+ S->ExportDynamic = true;
+ continue;
+ }
+
// 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.
@@ -1054,6 +1068,9 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
+ case Triple::amdgcn:
+ case Triple::r600:
+ return EM_AMDGPU;
case Triple::arm:
case Triple::thumb:
return EM_ARM;
@@ -1064,9 +1081,12 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
case Triple::mips64:
case Triple::mips64el:
return EM_MIPS;
+ case Triple::msp430:
+ return EM_MSP430;
case Triple::ppc:
return EM_PPC;
case Triple::ppc64:
+ case Triple::ppc64le:
return EM_PPC64;
case Triple::x86:
return T.isOSIAMCU() ? EM_IAMCU : EM_386;
@@ -1178,7 +1198,7 @@ static ELFKind getELFKind(MemoryBufferRef MB) {
}
void BinaryFile::parse() {
- ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer());
+ ArrayRef<uint8_t> Data = arrayRefFromStringRef(MB.getBuffer());
auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
8, Data, ".data");
Sections.push_back(Section);
@@ -1192,11 +1212,11 @@ void BinaryFile::parse() {
if (!isAlnum(S[I]))
S[I] = '_';
- Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0,
+ Symtab->addDefined(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0,
STB_GLOBAL, Section, nullptr);
- Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
+ Symtab->addDefined(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT,
Data.size(), 0, STB_GLOBAL, Section, nullptr);
- Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
+ Symtab->addDefined(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT,
Data.size(), 0, STB_GLOBAL, nullptr, nullptr);
}
@@ -1262,25 +1282,11 @@ template <class ELFT> void LazyObjFile::parse() {
return;
}
- switch (getELFKind(this->MB)) {
- case ELF32LEKind:
- addElfSymbols<ELF32LE>();
- return;
- case ELF32BEKind:
- addElfSymbols<ELF32BE>();
+ if (getELFKind(this->MB) != Config->EKind) {
+ error("incompatible file: " + this->MB.getBufferIdentifier());
return;
- case ELF64LEKind:
- addElfSymbols<ELF64LE>();
- return;
- case ELF64BEKind:
- addElfSymbols<ELF64BE>();
- return;
- default:
- llvm_unreachable("getELFKind");
}
-}
-template <class ELFT> void LazyObjFile::addElfSymbols() {
ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer()));
ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this);
@@ -1305,12 +1311,9 @@ std::string elf::replaceThinLTOSuffix(StringRef Path) {
StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first;
StringRef Repl = Config->ThinLTOObjectSuffixReplace.second;
- 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();
+ if (Path.consume_back(Suffix))
+ return (Path + Repl).str();
+ return Path;
}
template void ArchiveFile::parse<ELF32LE>();
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 0db3203b0ba2..5094ddd804a5 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -50,7 +50,7 @@ class Symbol;
// If -reproduce option is given, all input files are written
// to this tar archive.
-extern llvm::TarWriter *Tar;
+extern std::unique_ptr<llvm::TarWriter> Tar;
// Opens a given file.
llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
@@ -86,7 +86,9 @@ public:
// Returns object file symbols. It is a runtime error to call this
// function on files of other types.
- ArrayRef<Symbol *> getSymbols() {
+ ArrayRef<Symbol *> getSymbols() { return getMutableSymbols(); }
+
+ std::vector<Symbol *> &getMutableSymbols() {
assert(FileKind == BinaryKind || FileKind == ObjKind ||
FileKind == BitcodeKind);
return Symbols;
@@ -169,6 +171,7 @@ template <class ELFT> class ObjFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
typedef typename ELFT::Word Elf_Word;
+ typedef typename ELFT::CGProfile Elf_CGProfile;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@@ -218,6 +221,9 @@ public:
// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *AddrsigSec = nullptr;
+ // SHT_LLVM_CALL_GRAPH_PROFILE table
+ ArrayRef<Elf_CGProfile> CGProfile;
+
private:
void
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@@ -272,8 +278,6 @@ public:
bool AddedToLink = false;
private:
- template <class ELFT> void addElfSymbols();
-
uint64_t OffsetInArchive;
};
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 54fb57cf9888..839bff7011eb 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -21,7 +21,6 @@
#include "Thunks.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
@@ -64,11 +63,11 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
StringRef Name, Kind SectionKind)
: SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
Link),
- File(File), Data(Data) {
+ File(File), RawData(Data) {
// In order to reduce memory allocation, we assume that mergeable
// sections are smaller than 4 GiB, which is not an unreasonable
// assumption as of 2017.
- if (SectionKind == SectionBase::Merge && Data.size() > UINT32_MAX)
+ if (SectionKind == SectionBase::Merge && RawData.size() > UINT32_MAX)
error(toString(this) + ": section too large");
NumRelocations = 0;
@@ -80,6 +79,17 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
if (!isPowerOf2_64(V))
fatal(toString(File) + ": section sh_addralign is not a power of 2");
this->Alignment = V;
+
+ // In ELF, each section can be compressed by zlib, and if compressed,
+ // section name may be mangled by appending "z" (e.g. ".zdebug_info").
+ // If that's the case, demangle section name so that we can handle a
+ // section as if it weren't compressed.
+ if ((Flags & SHF_COMPRESSED) || Name.startswith(".zdebug")) {
+ if (!zlib::isAvailable())
+ error(toString(File) + ": contains a compressed section, " +
+ "but zlib is not available");
+ parseCompressedHeader();
+ }
}
// Drop SHF_GROUP bit unless we are producing a re-linkable object file.
@@ -128,13 +138,25 @@ InputSectionBase::InputSectionBase(ObjFile<ELFT> &File,
size_t InputSectionBase::getSize() const {
if (auto *S = dyn_cast<SyntheticSection>(this))
return S->getSize();
+ if (UncompressedSize >= 0)
+ return UncompressedSize;
+ return RawData.size();
+}
+
+void InputSectionBase::uncompress() const {
+ size_t Size = UncompressedSize;
+ UncompressedBuf.reset(new char[Size]);
- return Data.size();
+ if (Error E =
+ zlib::uncompress(toStringRef(RawData), UncompressedBuf.get(), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ RawData = makeArrayRef((uint8_t *)UncompressedBuf.get(), Size);
}
uint64_t InputSectionBase::getOffsetInFile() const {
const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
- const uint8_t *SecStart = Data.begin();
+ const uint8_t *SecStart = data().begin();
return SecStart - FileStart;
}
@@ -180,34 +202,70 @@ OutputSection *SectionBase::getOutputSection() {
return Sec ? Sec->getParent() : nullptr;
}
-// Decompress section contents if required. Note that this function
-// is called from parallelForEach, so it must be thread-safe.
-void InputSectionBase::maybeDecompress() {
- if (DecompressBuf)
- return;
- if (!(Flags & SHF_COMPRESSED) && !Name.startswith(".zdebug"))
- return;
+// When a section is compressed, `RawData` consists with a header followed
+// by zlib-compressed data. This function parses a header to initialize
+// `UncompressedSize` member and remove the header from `RawData`.
+void InputSectionBase::parseCompressedHeader() {
+ typedef typename ELF64LE::Chdr Chdr64;
+ typedef typename ELF32LE::Chdr Chdr32;
- // Decompress a section.
- Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
- Config->IsLE, Config->Is64));
+ // Old-style header
+ if (Name.startswith(".zdebug")) {
+ if (!toStringRef(RawData).startswith("ZLIB")) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+ RawData = RawData.slice(4);
- size_t Size = Dec.getDecompressedSize();
- 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)));
+ if (RawData.size() < 8) {
+ error(toString(this) + ": corrupted compressed section header");
+ return;
+ }
+
+ UncompressedSize = read64be(RawData.data());
+ RawData = RawData.slice(8);
+
+ // Restore the original section name.
+ // (e.g. ".zdebug_info" -> ".debug_info")
+ Name = Saver.save("." + Name.substr(2));
+ return;
+ }
- Data = makeArrayRef((uint8_t *)DecompressBuf.get(), Size);
+ assert(Flags & SHF_COMPRESSED);
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);
+ // New-style 64-bit header
+ if (Config->Is64) {
+ if (RawData.size() < sizeof(Chdr64)) {
+ error(toString(this) + ": corrupted compressed section");
+ return;
+ }
+
+ auto *Hdr = reinterpret_cast<const Chdr64 *>(RawData.data());
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
+ error(toString(this) + ": unsupported compression type");
+ return;
+ }
+
+ UncompressedSize = Hdr->ch_size;
+ RawData = RawData.slice(sizeof(*Hdr));
+ return;
}
+
+ // New-style 32-bit header
+ if (RawData.size() < sizeof(Chdr32)) {
+ error(toString(this) + ": corrupted compressed section");
+ return;
+ }
+
+ auto *Hdr = reinterpret_cast<const Chdr32 *>(RawData.data());
+ if (Hdr->ch_type != ELFCOMPRESS_ZLIB) {
+ error(toString(this) + ": unsupported compression type");
+ return;
+ }
+
+ UncompressedSize = Hdr->ch_size;
+ RawData = RawData.slice(sizeof(*Hdr));
}
InputSection *InputSectionBase::getLinkOrderDep() const {
@@ -230,14 +288,17 @@ Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) {
// Returns a source location string. Used to construct an error message.
template <class ELFT>
std::string InputSectionBase::getLocation(uint64_t Offset) {
+ std::string SecAndOffset = (Name + "+0x" + utohexstr(Offset)).str();
+
// We don't have file for synthetic sections.
if (getFile<ELFT>() == nullptr)
- return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")")
+ return (Config->OutputFile + ":(" + SecAndOffset + ")")
.str();
// First check if we can get desired values from debugging information.
if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset))
- return Info->FileName + ":" + std::to_string(Info->Line);
+ return Info->FileName + ":" + std::to_string(Info->Line) + ":(" +
+ SecAndOffset + ")";
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
@@ -246,10 +307,10 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
SrcFile = toString(File);
if (Defined *D = getEnclosingFunction<ELFT>(Offset))
- return SrcFile + ":(function " + toString(*D) + ")";
+ return SrcFile + ":(function " + toString(*D) + ": " + SecAndOffset + ")";
// If there's no symbol, print out the offset in the section.
- return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
+ return (SrcFile + ":(" + SecAndOffset + ")");
}
// This function is intended to be used for constructing an error message.
@@ -259,9 +320,6 @@ std::string InputSectionBase::getLocation(uint64_t Offset) {
//
// Returns an empty string if there's no way to get line info.
std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
- // Synthetic sections don't have input files.
- if (!File)
- return "";
return File->getSrcMsg(Sym, *this, Offset);
}
@@ -275,9 +333,6 @@ std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) {
//
// path/to/foo.o:(function bar) in archive path/to/bar.a
std::string InputSectionBase::getObjMsg(uint64_t Off) {
- // Synthetic sections don't have input files.
- if (!File)
- return ("<internal>:(" + Name + "+0x" + utohexstr(Off) + ")").str();
std::string Filename = File->getName();
std::string Archive;
@@ -362,7 +417,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
// 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->getVA(Rel.r_offset);
- P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type,
+ P->setSymbolAndType(In.SymTab->getSymbolIndex(&Sym), Type,
Config->IsMips64EL);
if (Sym.Type == STT_SECTION) {
@@ -380,14 +435,14 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
error("STT_SECTION symbol should be defined");
continue;
}
- SectionBase *Section = D->Section;
- if (Section == &InputSection::Discarded) {
+ SectionBase *Section = D->Section->Repl;
+ if (!Section->Live) {
P->setSymbolAndType(0, 0, false);
continue;
}
int64_t Addend = getAddend<ELFT>(Rel);
- const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset;
+ const uint8_t *BufLoc = Sec->data().begin() + Rel.r_offset;
if (!RelTy::IsRela)
Addend = Target->getImplicitAddend(BufLoc, Type);
@@ -487,6 +542,62 @@ static uint64_t getARMStaticBase(const Symbol &Sym) {
return OS->PtLoad->FirstSec->Addr;
}
+// For R_RISCV_PC_INDIRECT (R_RISCV_PCREL_LO12_{I,S}), the symbol actually
+// points the corresponding R_RISCV_PCREL_HI20 relocation, and the target VA
+// is calculated using PCREL_HI20's symbol.
+//
+// This function returns the R_RISCV_PCREL_HI20 relocation from
+// R_RISCV_PCREL_LO12's symbol and addend.
+static Relocation *getRISCVPCRelHi20(const Symbol *Sym, uint64_t Addend) {
+ const Defined *D = cast<Defined>(Sym);
+ InputSection *IS = cast<InputSection>(D->Section);
+
+ if (Addend != 0)
+ warn("Non-zero addend in R_RISCV_PCREL_LO12 relocation to " +
+ IS->getObjMsg(D->Value) + " is ignored");
+
+ // Relocations are sorted by offset, so we can use std::equal_range to do
+ // binary search.
+ auto Range = std::equal_range(IS->Relocations.begin(), IS->Relocations.end(),
+ D->Value, RelocationOffsetComparator{});
+ for (auto It = std::get<0>(Range); It != std::get<1>(Range); ++It)
+ if (isRelExprOneOf<R_PC>(It->Expr))
+ return &*It;
+
+ error("R_RISCV_PCREL_LO12 relocation points to " + IS->getObjMsg(D->Value) +
+ " without an associated R_RISCV_PCREL_HI20 relocation");
+ return nullptr;
+}
+
+// A TLS symbol's virtual address is relative to the TLS segment. Add a
+// target-specific adjustment to produce a thread-pointer-relative offset.
+static int64_t getTlsTpOffset() {
+ switch (Config->EMachine) {
+ case EM_ARM:
+ case EM_AARCH64:
+ // Variant 1. The thread pointer points to a TCB with a fixed 2-word size,
+ // followed by a variable amount of alignment padding, followed by the TLS
+ // segment.
+ //
+ // NB: While the ARM/AArch64 ABI formally has a 2-word TCB size, lld
+ // effectively increases the TCB size to 8 words for Android compatibility.
+ // It accomplishes this by increasing the segment's alignment.
+ return alignTo(Config->Wordsize * 2, Out::TlsPhdr->p_align);
+ case EM_386:
+ case EM_X86_64:
+ // Variant 2. The TLS segment is located just before the thread pointer.
+ return -Out::TlsPhdr->p_memsz;
+ case EM_PPC64:
+ // The thread pointer points to a fixed offset from the start of the
+ // executable's TLS segment. An offset of 0x7000 allows a signed 16-bit
+ // offset to reach 0x1000 of TCB/thread-library data and 0xf000 of the
+ // program's TLS segment.
+ return -0x7000;
+ default:
+ llvm_unreachable("unhandled Config->EMachine");
+ }
+}
+
static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
uint64_t P, const Symbol &Sym, RelExpr Expr) {
switch (Expr) {
@@ -501,38 +612,37 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
case R_ARM_SBREL:
return Sym.getVA(A) - getARMStaticBase(Sym);
case R_GOT:
+ case R_GOT_PLT:
case R_RELAX_TLS_GD_TO_IE_ABS:
return Sym.getGotVA() + A;
case R_GOTONLY_PC:
- return InX::Got->getVA() + A - P;
+ return In.Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
- return InX::Got->getVA() + A - P + InX::Got->getSize();
+ return In.Got->getVA() + A - P + In.Got->getSize();
case R_GOTREL:
- return Sym.getVA(A) - InX::Got->getVA();
+ return Sym.getVA(A) - In.Got->getVA();
case R_GOTREL_FROM_END:
- return Sym.getVA(A) - InX::Got->getVA() - InX::Got->getSize();
+ return Sym.getVA(A) - In.Got->getVA() - In.Got->getSize();
case R_GOT_FROM_END:
case R_RELAX_TLS_GD_TO_IE_END:
- return Sym.getGotOffset() + A - InX::Got->getSize();
+ return Sym.getGotOffset() + A - In.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:
+ case R_AARCH64_GOT_PAGE_PC:
+ case R_AARCH64_GOT_PAGE_PC_PLT:
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
case R_GOT_PC:
case R_RELAX_TLS_GD_TO_IE:
return Sym.getGotVA() + A - P;
- case R_HINT:
- case R_NONE:
- case R_TLSDESC_CALL:
- case R_TLSLD_HINT:
- llvm_unreachable("cannot relocate hint relocs");
+ case R_HEXAGON_GOT:
+ return Sym.getGotVA() - In.GotPlt->getVA();
case R_MIPS_GOTREL:
- return Sym.getVA(A) - InX::MipsGot->getGp(File);
+ return Sym.getVA(A) - In.MipsGot->getGp(File);
case R_MIPS_GOT_GP:
- return InX::MipsGot->getGp(File) + A;
+ return In.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
@@ -541,7 +651,7 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// 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(File) + A - P;
+ uint64_t V = In.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)
@@ -552,31 +662,34 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// 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(File, Sym, A) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getPageEntryOffset(File, Sym, A) -
+ In.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(File, Sym, A) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getSymEntryOffset(File, Sym, A) -
+ In.MipsGot->getGp(File);
case R_MIPS_TLSGD:
- return InX::MipsGot->getVA() + InX::MipsGot->getGlobalDynOffset(File, Sym) -
- InX::MipsGot->getGp(File);
+ return In.MipsGot->getVA() + In.MipsGot->getGlobalDynOffset(File, Sym) -
+ In.MipsGot->getGp(File);
case R_MIPS_TLSLD:
- return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) -
- InX::MipsGot->getGp(File);
- case R_PAGE_PC:
- case R_PLT_PAGE_PC: {
- uint64_t Dest;
- if (Sym.isUndefWeak())
- Dest = getAArch64Page(A);
- else
- Dest = getAArch64Page(Sym.getVA(A));
- return Dest - getAArch64Page(P);
+ return In.MipsGot->getVA() + In.MipsGot->getTlsIndexOffset(File) -
+ In.MipsGot->getGp(File);
+ case R_AARCH64_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_AARCH64_PLT_PAGE_PC: {
+ uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
+ return getAArch64Page(Val) - getAArch64Page(P);
+ }
+ case R_RISCV_PC_INDIRECT: {
+ if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
+ return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),
+ *HiRel->Sym, HiRel->Expr);
+ return 0;
}
case R_PC: {
uint64_t Dest;
@@ -608,16 +721,12 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
return 0;
// 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);
+ // point is used for calls where the caller and callee (may) have different
+ // TOC base pointers and r2 needs to be modified to hold the TOC base for
+ // the callee. For local calls the caller and callee share the same
+ // TOC base and so the TOC pointer initialization code should be skipped by
+ // branching to the local entry point.
+ return SymVA - P + getPPC64GlobalEntryToLocalEntryOffset(Sym.StOther);
}
case R_PPC_TOC:
return getPPC64TocBase() + A;
@@ -634,48 +743,32 @@ static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A,
// statically to zero.
if (Sym.isTls() && Sym.isUndefWeak())
return 0;
-
- // 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;
+ return Sym.getVA(A) + getTlsTpOffset();
case R_RELAX_TLS_GD_TO_LE_NEG:
case R_NEG_TLS:
return Out::TlsPhdr->p_memsz - Sym.getVA(A);
case R_SIZE:
return Sym.getSize() + A;
case R_TLSDESC:
- return InX::Got->getGlobalDynAddr(Sym) + A;
- case R_TLSDESC_PAGE:
- return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) -
+ return In.Got->getGlobalDynAddr(Sym) + A;
+ case R_AARCH64_TLSDESC_PAGE:
+ return getAArch64Page(In.Got->getGlobalDynAddr(Sym) + A) -
getAArch64Page(P);
case R_TLSGD_GOT:
- return InX::Got->getGlobalDynOffset(Sym) + A;
+ return In.Got->getGlobalDynOffset(Sym) + A;
case R_TLSGD_GOT_FROM_END:
- return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize();
+ return In.Got->getGlobalDynOffset(Sym) + A - In.Got->getSize();
case R_TLSGD_PC:
- return InX::Got->getGlobalDynAddr(Sym) + A - P;
+ return In.Got->getGlobalDynAddr(Sym) + A - P;
case R_TLSLD_GOT_FROM_END:
- return InX::Got->getTlsIndexOff() + A - InX::Got->getSize();
+ return In.Got->getTlsIndexOff() + A - In.Got->getSize();
case R_TLSLD_GOT:
- return InX::Got->getTlsIndexOff() + A;
+ return In.Got->getTlsIndexOff() + A;
case R_TLSLD_PC:
- return InX::Got->getTlsIndexVA() + A - P;
+ return In.Got->getTlsIndexVA() + A - P;
+ default:
+ llvm_unreachable("invalid expression");
}
- llvm_unreachable("Invalid expression");
}
// This function applies relocations to sections without SHF_ALLOC bit.
@@ -808,10 +901,10 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) {
case R_RELAX_TLS_GD_TO_LE_NEG:
Target->relaxTlsGdToLe(BufLoc, Type, TargetVA);
break;
+ case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
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;
@@ -848,16 +941,20 @@ static void switchMorestackCallsToMorestackNonSplit(
// __morestack inside that function should be switched to
// __morestack_non_split.
Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split");
+ if (!MoreStackNonSplit) {
+ error("Mixing split-stack objects requires a definition of "
+ "__morestack_non_split");
+ return;
+ }
// Sort both collections to compare addresses efficiently.
- llvm::sort(MorestackCalls.begin(), MorestackCalls.end(),
- [](const Relocation *L, const Relocation *R) {
- return L->Offset < R->Offset;
- });
+ llvm::sort(MorestackCalls, [](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; });
+ llvm::sort(Functions, [](const Defined *L, const Defined *R) {
+ return L->Value < R->Value;
+ });
auto It = MorestackCalls.begin();
for (Defined *F : Functions) {
@@ -872,8 +969,8 @@ static void switchMorestackCallsToMorestackNonSplit(
}
}
-static bool enclosingPrologueAdjusted(uint64_t Offset,
- const DenseSet<Defined *> &Prologues) {
+static bool enclosingPrologueAttempted(uint64_t Offset,
+ const DenseSet<Defined *> &Prologues) {
for (Defined *F : Prologues)
if (F->Value <= Offset && Offset < F->Value + F->Size)
return true;
@@ -889,7 +986,7 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
uint8_t *End) {
if (!getFile<ELFT>()->SplitStack)
return;
- DenseSet<Defined *> AdjustedPrologues;
+ DenseSet<Defined *> Prologues;
std::vector<Relocation *> MorestackCalls;
for (Relocation &Rel : Relocations) {
@@ -898,15 +995,9 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
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"))
+ if (Rel.Sym->getName().startswith("__morestack")) {
+ if (Rel.Sym->getName().equals("__morestack"))
MorestackCalls.push_back(&Rel);
continue;
}
@@ -914,24 +1005,36 @@ void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf,
// 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)
+ if (Rel.Sym->Type != STT_FUNC)
continue;
- if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues))
+ // If the callee's-file was compiled with split stack, nothing to do. In
+ // this context, a "Defined" symbol is one "defined by the binary currently
+ // being produced". So an "undefined" symbol might be provided by a shared
+ // library. It is not possible to tell how such symbols were compiled, so be
+ // conservative.
+ if (Defined *D = dyn_cast<Defined>(Rel.Sym))
+ if (InputSection *IS = cast_or_null<InputSection>(D->Section))
+ if (!IS || !IS->getFile<ELFT>() || IS->getFile<ELFT>()->SplitStack)
+ continue;
+
+ if (enclosingPrologueAttempted(Rel.Offset, Prologues))
continue;
if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) {
- if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) {
- AdjustedPrologues.insert(F);
+ Prologues.insert(F);
+ if (Target->adjustPrologueForCrossSplitStack(Buf + getOffset(F->Value),
+ End, F->StOther))
continue;
- }
+ if (!getFile<ELFT>()->SomeNoSplitStack)
+ error(lld::toString(this) + ": " + F->getName() +
+ " (with -fsplit-stack) calls " + Rel.Sym->getName() +
+ " (without -fsplit-stack), but couldn't adjust its prologue");
}
- 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);
+
+ if (Target->NeedsMoreStackNonSplit)
+ switchMorestackCallsToMorestackNonSplit(Prologues, MorestackCalls);
}
template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
@@ -960,10 +1063,23 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
return;
}
+ // If this is a compressed section, uncompress section contents directly
+ // to the buffer.
+ if (UncompressedSize >= 0 && !UncompressedBuf) {
+ size_t Size = UncompressedSize;
+ if (Error E = zlib::uncompress(toStringRef(RawData),
+ (char *)(Buf + OutSecOff), Size))
+ fatal(toString(this) +
+ ": uncompress failed: " + llvm::toString(std::move(E)));
+ uint8_t *BufEnd = Buf + OutSecOff + Size;
+ relocate<ELFT>(Buf, BufEnd);
+ return;
+ }
+
// Copy section contents from source object file to output file
// and then apply relocations.
- memcpy(Buf + OutSecOff, Data.data(), Data.size());
- uint8_t *BufEnd = Buf + OutSecOff + Data.size();
+ memcpy(Buf + OutSecOff, data().data(), data().size());
+ uint8_t *BufEnd = Buf + OutSecOff + data().size();
relocate<ELFT>(Buf, BufEnd);
}
@@ -1014,7 +1130,7 @@ template <class ELFT> void EhInputSection::split() {
template <class ELFT, class RelTy>
void EhInputSection::split(ArrayRef<RelTy> Rels) {
unsigned RelI = 0;
- for (size_t Off = 0, End = Data.size(); Off != End;) {
+ for (size_t Off = 0, End = data().size(); Off != End;) {
size_t Size = readEhRecordSize(this, Off);
Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
@@ -1094,65 +1210,32 @@ void MergeInputSection::splitIntoPieces() {
assert(Pieces.empty());
if (Flags & SHF_STRINGS)
- splitStrings(Data, Entsize);
+ splitStrings(data(), Entsize);
else
- splitNonStrings(Data, Entsize);
-
- 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>
-static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
- size_t Size = std::distance(First, Last);
- assert(Size != 0);
- while (Size != 1) {
- size_t H = Size / 2;
- const It MI = First + H;
- Size -= H;
- First = Comp(Value, *MI) ? First : First + H;
- }
- return Comp(Value, *First) ? First : First + 1;
-}
-
-// 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(
- Sec->Pieces.begin(), Sec->Pieces.end(), Offset,
- [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
- --I;
- return &*I;
+ splitNonStrings(data(), Entsize);
}
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 (this->data().size() <= Offset)
+ fatal(toString(this) + ": offset is outside the section");
// 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);
+ // In that case we need to do a binary search of the original section piece vector.
+ auto It2 =
+ llvm::upper_bound(Pieces, Offset, [](uint64_t Offset, SectionPiece P) {
+ return Offset < P.InputOff;
+ });
+ return &It2[-1];
}
// 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::getParentOffset(uint64_t Offset) const {
- // Find a string starting at a given offset.
- auto It = OffsetMap.find(Offset);
- if (It != OffsetMap.end())
- return Pieces[It->second].OutputOff;
-
// 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 =
- *findSectionPiece(const_cast<MergeInputSection *>(this), Offset);
+ *(const_cast<MergeInputSection *>(this)->getSectionPiece (Offset));
uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 4db01e035e32..34f411e87200 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -115,7 +115,12 @@ public:
return cast_or_null<ObjFile<ELFT>>(File);
}
- ArrayRef<uint8_t> Data;
+ ArrayRef<uint8_t> data() const {
+ if (UncompressedSize >= 0 && !UncompressedBuf)
+ uncompress();
+ return RawData;
+ }
+
uint64_t getOffsetInFile() const;
// True if this section has already been placed to a linker script
@@ -169,11 +174,6 @@ public:
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 maybeDecompress();
-
// Returns a source location string. Used to construct an error message.
template <class ELFT> std::string getLocation(uint64_t Offset);
std::string getSrcMsg(const Symbol &Sym, uint64_t Offset);
@@ -200,15 +200,21 @@ public:
template <typename T> llvm::ArrayRef<T> getDataAs() const {
- size_t S = Data.size();
+ size_t S = data().size();
assert(S % sizeof(T) == 0);
- return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ return llvm::makeArrayRef<T>((const T *)data().data(), S / sizeof(T));
}
-private:
- // A pointer that owns decompressed data if a section is compressed by zlib.
+protected:
+ void parseCompressedHeader();
+ void uncompress() const;
+
+ mutable ArrayRef<uint8_t> RawData;
+
+ // A pointer that owns uncompressed data if a section is compressed by zlib.
// Since the feature is not used often, this is usually a nullptr.
- std::unique_ptr<char[]> DecompressBuf;
+ mutable std::unique_ptr<char[]> UncompressedBuf;
+ int64_t UncompressedSize = -1;
};
// SectionPiece represents a piece of splittable section contents.
@@ -247,7 +253,6 @@ public:
// 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.
@@ -255,8 +260,8 @@ public:
llvm::CachedHashStringRef getData(size_t I) const {
size_t Begin = Pieces[I].InputOff;
size_t End =
- (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff;
- return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash};
+ (Pieces.size() - 1 == I) ? data().size() : Pieces[I + 1].InputOff;
+ return {toStringRef(data().slice(Begin, End - Begin)), Pieces[I].Hash};
}
// Returns the SectionPiece at a given input section offset.
@@ -277,7 +282,9 @@ struct EhSectionPiece {
unsigned FirstRelocation)
: InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {}
- ArrayRef<uint8_t> data() { return {Sec->Data.data() + this->InputOff, Size}; }
+ ArrayRef<uint8_t> data() {
+ return {Sec->data().data() + this->InputOff, Size};
+ }
size_t InputOff;
ssize_t OutputOff = -1;
@@ -353,6 +360,7 @@ private:
// The list of all input sections.
extern std::vector<InputSectionBase *> InputSections;
+
} // namespace elf
std::string toString(const elf::InputSectionBase *);
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index ef58932e86cc..ca44581780e4 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -67,9 +67,10 @@ static std::string getThinLTOOutputFile(StringRef ModulePath) {
static lto::Config createConfig() {
lto::Config C;
- // LLD supports the new relocations.
+ // LLD supports the new relocations and address-significance tables.
C.Options = InitTargetOptionsFromCodeGenFlags();
C.Options.RelaxELFRelocations = true;
+ C.Options.EmitAddrsig = true;
// Always emit a section per function/datum with LTO.
C.Options.FunctionSections = true;
@@ -87,6 +88,7 @@ static lto::Config createConfig() {
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
C.CPU = GetCPUStr();
+ C.MAttrs = GetMAttrs();
// Set up a custom pipeline if we've been asked to.
C.OptPipeline = Config->LTONewPmPasses;
@@ -101,6 +103,14 @@ static lto::Config createConfig() {
C.DebugPassManager = Config->LTODebugPassManager;
C.DwoDir = Config->DwoDir;
+ if (Config->EmitLLVM) {
+ C.PostInternalizeModuleHook = [](size_t Task, const Module &M) {
+ if (std::unique_ptr<raw_fd_ostream> OS = openFile(Config->OutputFile))
+ WriteBitcodeToFile(M, *OS, false);
+ return false;
+ };
+ }
+
if (Config->SaveTemps)
checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
/*UseInputModulePath*/ true));
@@ -108,18 +118,14 @@ static lto::Config createConfig() {
}
BitcodeCompiler::BitcodeCompiler() {
+ // Initialize IndexFile.
+ if (!Config->ThinLTOIndexOnlyArg.empty())
+ IndexFile = openFile(Config->ThinLTOIndexOnlyArg);
+
// Initialize LTOObj.
lto::ThinBackend Backend;
-
if (Config->ThinLTOIndexOnly) {
- StringRef Path = Config->ThinLTOIndexOnlyArg;
- if (!Path.empty())
- IndexFile = openFile(Path);
-
- auto OnIndexWrite = [&](const std::string &Identifier) {
- ObjectToIndexFileState[Identifier] = true;
- };
-
+ auto OnIndexWrite = [&](StringRef S) { ThinIndices.erase(S); };
Backend = lto::createWriteIndexesThinBackend(
Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second,
Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite);
@@ -132,10 +138,10 @@ BitcodeCompiler::BitcodeCompiler() {
// Initialize UsedStartStop.
for (Symbol *Sym : Symtab->getSymbols()) {
- StringRef Name = Sym->getName();
+ StringRef S = Sym->getName();
for (StringRef Prefix : {"__start_", "__stop_"})
- if (Name.startswith(Prefix))
- UsedStartStop.insert(Name.substr(Prefix.size()));
+ if (S.startswith(Prefix))
+ UsedStartStop.insert(S.substr(Prefix.size()));
}
}
@@ -151,7 +157,7 @@ void BitcodeCompiler::add(BitcodeFile &F) {
bool IsExec = !Config->Shared && !Config->Relocatable;
if (Config->ThinLTOIndexOnly)
- ObjectToIndexFileState.insert({Obj.getName(), false});
+ ThinIndices.insert(Obj.getName());
ArrayRef<Symbol *> Syms = F.getSymbols();
ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols();
@@ -240,15 +246,11 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
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");
- }
+ for (StringRef S : ThinIndices) {
+ std::string Path = getThinLTOOutputFile(S);
+ openFile(Path + ".thinlto.bc");
+ if (Config->ThinLTOEmitImportsFiles)
+ openFile(Path + ".imports");
}
// If LazyObjFile has not been added to link, emit empty index files.
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 8803078eb1df..a190da3e5996 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -55,7 +55,7 @@ private:
std::vector<std::unique_ptr<MemoryBuffer>> Files;
llvm::DenseSet<StringRef> UsedStartStop;
std::unique_ptr<llvm::raw_fd_ostream> IndexFile;
- llvm::StringMap<bool> ObjectToIndexFileState;
+ llvm::DenseSet<StringRef> ThinIndices;
};
} // namespace elf
} // namespace lld
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index abdd899da487..fbc025416205 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -116,7 +116,8 @@ void LinkerScript::expandMemoryRegions(uint64_t Size) {
if (Ctx->MemRegion)
expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name,
Ctx->OutSec->Name);
- if (Ctx->LMARegion)
+ // Only expand the LMARegion if it is different from MemRegion.
+ if (Ctx->LMARegion && Ctx->MemRegion != Ctx->LMARegion)
expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name,
Ctx->OutSec->Name);
}
@@ -168,7 +169,7 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
// Define a symbol.
Symbol *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility,
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, Visibility,
/*CanOmitFromDynSym*/ false,
/*File*/ nullptr);
ExprValue Value = Cmd->Expression();
@@ -201,13 +202,14 @@ static void declareSymbol(SymbolAssignment *Cmd) {
// 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,
+ std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, 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;
+ Sym->ScriptDefined = true;
}
// This method is used to handle INSERT AFTER statement. Here we rebuild
@@ -413,18 +415,16 @@ 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::RelaPlt || S == InX::RelaDyn ||
- S == InX::RelrDyn)
+ if (S == In.ShStrTab || S == In.RelaDyn || S == In.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;
+ if (S == In.GnuHashTab)
+ In.GnuHashTab = nullptr;
+ if (S == In.HashTab)
+ In.HashTab = nullptr;
S->Assigned = false;
S->Live = false;
@@ -700,6 +700,7 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Alignment) {
}
void LinkerScript::output(InputSection *S) {
+ assert(Ctx->OutSec == S->getParent());
uint64_t Before = advance(0, 1);
uint64_t Pos = advance(S->getSize(), S->Alignment);
S->OutSecOff = Pos - S->getSize() - Ctx->OutSec->Addr;
@@ -750,6 +751,13 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) {
return nullptr;
}
+static OutputSection *findFirstSection(PhdrEntry *Load) {
+ for (OutputSection *Sec : OutputSections)
+ if (Sec->PtLoad == Load)
+ return Sec;
+ return nullptr;
+}
+
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
void LinkerScript::assignOffsets(OutputSection *Sec) {
@@ -775,8 +783,11 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
// 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
+ // This, however, should only be done by the first "non-header" section
+ // in the segment.
if (PhdrEntry *L = Ctx->OutSec->PtLoad)
- L->LMAOffset = Ctx->LMAOffset;
+ if (Sec == findFirstSection(L))
+ L->LMAOffset = Ctx->LMAOffset;
// We can call this method multiple times during the creation of
// thunks and want to start over calculation each time.
@@ -805,21 +816,8 @@ void LinkerScript::assignOffsets(OutputSection *Sec) {
// Handle a single input section description command.
// It calculates and assigns the offsets for each section and also
// updates the output section size.
- auto *Cmd = cast<InputSectionDescription>(Base);
- for (InputSection *Sec : Cmd->Sections) {
- // We tentatively added all synthetic sections at the beginning and
- // removed empty ones afterwards (because there is no way to know
- // whether they were going be empty or not other than actually running
- // linker scripts.) We need to ignore remains of empty sections.
- if (auto *S = dyn_cast<SyntheticSection>(Sec))
- if (S->empty())
- continue;
-
- if (!Sec->Live)
- continue;
- assert(Ctx->OutSec == Sec->getParent());
+ for (InputSection *Sec : cast<InputSectionDescription>(Base)->Sections)
output(Sec);
- }
}
}
@@ -953,13 +951,6 @@ void LinkerScript::adjustSectionsAfterSorting() {
}
}
-static OutputSection *findFirstSection(PhdrEntry *Load) {
- for (OutputSection *Sec : OutputSections)
- if (Sec->PtLoad == Load)
- return Sec;
- 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.
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 3b790dd4669f..51161981efc8 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -30,12 +30,13 @@ namespace lld {
namespace elf {
class Defined;
-class Symbol;
-class InputSectionBase;
class InputSection;
-class OutputSection;
class InputSectionBase;
+class InputSectionBase;
+class OutputSection;
class SectionBase;
+class Symbol;
+class ThunkSection;
// This represents an r-value in the linker script.
struct ExprValue {
@@ -145,7 +146,9 @@ struct MemoryRegion {
// Also it may be surrounded with SORT() command, so contains sorting rules.
struct SectionPattern {
SectionPattern(StringMatcher &&Pat1, StringMatcher &&Pat2)
- : ExcludedFilePat(Pat1), SectionPat(Pat2) {}
+ : ExcludedFilePat(Pat1), SectionPat(Pat2),
+ SortOuter(SortSectionPolicy::Default),
+ SortInner(SortSectionPolicy::Default) {}
StringMatcher ExcludedFilePat;
StringMatcher SectionPat;
@@ -153,7 +156,6 @@ struct SectionPattern {
SortSectionPolicy SortInner;
};
-class ThunkSection;
struct InputSectionDescription : BaseCommand {
InputSectionDescription(StringRef FilePattern)
: BaseCommand(InputSectionKind), FilePat(FilePattern) {}
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
index 54fddfb7b299..b0dc6203008d 100644
--- a/ELF/MapFile.cpp
+++ b/ELF/MapFile.cpp
@@ -126,7 +126,7 @@ static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
};
// Gather section pieces.
- for (const CieRecord *Rec : InX::EhFrame->getCieRecords()) {
+ for (const CieRecord *Rec : In.EhFrame->getCieRecords()) {
Add(*Rec->Cie);
for (const EhSectionPiece *Fde : Rec->Fdes)
Add(*Fde);
@@ -163,17 +163,18 @@ void elf::writeMapFile() {
OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
<< " Size Align Out In Symbol\n";
+ OutputSection* OSec = nullptr;
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);
+ uint64_t LMA = OSec ? OSec->getLMA() + Cmd->Addr - OSec->getVA(0) : 0;
+ writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1);
OS << Cmd->CommandString << '\n';
continue;
}
- auto *OSec = cast<OutputSection>(Base);
+ OSec = cast<OutputSection>(Base);
writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
OS << OSec->Name << '\n';
@@ -181,7 +182,7 @@ void elf::writeMapFile() {
for (BaseCommand *Base : OSec->SectionCommands) {
if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
for (InputSection *IS : ISD->Sections) {
- if (IS == InX::EhFrame) {
+ if (IS == In.EhFrame) {
printEhFrame(OS, OSec);
continue;
}
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index a8371e212c3e..8d0ec091c327 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -45,7 +45,7 @@ using namespace lld::elf;
template <class ELFT>
static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rel &Rel) {
- return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
+ return Target->getImplicitAddend(Sec.data().begin() + Rel.r_offset,
Rel.getType(Config->IsMips64EL));
}
@@ -250,9 +250,10 @@ template <class ELFT> static void doGcSections() {
if (Sec->Flags & SHF_LINK_ORDER)
continue;
- if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
+
+ if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec)) {
Enqueue(Sec, 0);
- else if (isValidCIdentifier(Sec->Name)) {
+ } else if (isValidCIdentifier(Sec->Name)) {
CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
CNamedSections[Saver.save("__stop_" + Sec->Name)].push_back(Sec);
}
@@ -267,10 +268,16 @@ template <class ELFT> static void doGcSections() {
// input sections. This function make some or all of them on
// so that they are emitted to the output file.
template <class ELFT> void elf::markLive() {
- // If -gc-sections is missing, no sections are removed.
if (!Config->GcSections) {
+ // If -gc-sections is missing, no sections are removed.
for (InputSectionBase *Sec : InputSections)
Sec->Live = true;
+
+ // If a DSO defines a symbol referenced in a regular object, it is needed.
+ for (Symbol *Sym : Symtab->getSymbols())
+ if (auto *S = dyn_cast<SharedSymbol>(Sym))
+ if (S->IsUsedInRegularObj && !S->isWeak())
+ S->getFile<ELFT>().IsNeeded = true;
return;
}
diff --git a/ELF/Options.td b/ELF/Options.td
index 04a4f8ffbe28..e43a21b923d3 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -42,6 +42,12 @@ defm compress_debug_sections:
defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">;
+defm split_stack_adjust_size
+ : Eq<"split-stack-adjust-size",
+ "Specify adjustment to stack size when a split-stack function calls a "
+ "non-split-stack function">,
+ MetaVarName<"<value>">;
+
defm library_path:
Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">;
@@ -68,6 +74,10 @@ defm as_needed: B<"as-needed",
defm call_graph_ordering_file:
Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">;
+defm call_graph_profile_sort: B<"call-graph-profile-sort",
+ "Reorder sections with call graph profile (default)",
+ "Do not reorder sections with call graph profile">;
+
// -chroot doesn't have a help text because it is an internal option.
def chroot: Separate<["--", "-"], "chroot">;
@@ -132,7 +142,7 @@ def error_unresolved_symbols: F<"error-unresolved-symbols">,
defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm execute_only: B<"execute-only",
- "Do not mark executable sections readable",
+ "Mark executable sections unreadable",
"Mark executable sections readable (default)">;
defm export_dynamic: B<"export-dynamic",
@@ -315,6 +325,10 @@ defm threads: B<"threads",
"Run the linker multi-threaded (default)",
"Do not run the linker multi-threaded">;
+defm toc_optimize : B<"toc-optimize",
+ "(PowerPC64) Enable TOC related optimizations (default)",
+ "(PowerPC64) Disable TOC related optimizations">;
+
def trace: F<"trace">, HelpText<"Print the names of the input files">;
defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">;
@@ -348,6 +362,10 @@ defm warn_common: B<"warn-common",
"Warn about duplicate common symbols",
"Do not warn about duplicate common symbols (default)">;
+defm warn_ifunc_textrel: B<"warn-ifunc-textrel",
+ "Warn about using ifunc symbols with text relocations",
+ "Do not warn about using ifunc symbols with text relocations (default)">;
+
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">;
@@ -440,6 +458,7 @@ def: F<"plugin-opt=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 plugin_opt_emit_llvm: F<"plugin-opt=emit-llvm">;
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=">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 8253b18b486c..c1442c078736 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -25,6 +25,7 @@
using namespace llvm;
using namespace llvm::dwarf;
using namespace llvm::object;
+using namespace llvm::support::endian;
using namespace llvm::ELF;
using namespace lld;
@@ -32,7 +33,6 @@ using namespace lld::elf;
uint8_t Out::First;
PhdrEntry *Out::TlsPhdr;
-OutputSection *Out::DebugInfo;
OutputSection *Out::ElfHeader;
OutputSection *Out::ProgramHeaders;
OutputSection *Out::PreinitArray;
@@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) {
Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
- unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
+ unsigned Mask = 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 +
@@ -171,11 +171,12 @@ void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) {
// Fill [Buf, Buf + Size) with Filler.
// This is used for linker script "=fillexp" command.
-static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
+static void fill(uint8_t *Buf, size_t Size,
+ const std::array<uint8_t, 4> &Filler) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, &Filler, 4);
- memcpy(Buf + I, &Filler, Size - I);
+ memcpy(Buf + I, Filler.data(), 4);
+ memcpy(Buf + I, Filler.data(), Size - I);
}
// Compress section contents if this section contains debug info.
@@ -236,8 +237,9 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
// Write leading padding.
std::vector<InputSection *> Sections = getInputSections(this);
- uint32_t Filler = getFiller();
- if (Filler)
+ std::array<uint8_t, 4> Filler = getFiller();
+ bool NonZeroFiller = read32(Filler.data()) != 0;
+ if (NonZeroFiller)
fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
parallelForEachN(0, Sections.size(), [&](size_t I) {
@@ -245,7 +247,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
IS->writeTo<ELFT>(Buf);
// Fill gaps between sections.
- if (Filler) {
+ if (NonZeroFiller) {
uint8_t *Start = Buf + IS->OutSecOff + IS->getSize();
uint8_t *End;
if (I + 1 == Sections.size())
@@ -270,13 +272,13 @@ static void finalizeShtGroup(OutputSection *OS,
// sh_link field for SHT_GROUP sections should contain the section index of
// the symbol table.
- OS->Link = InX::SymTab->getParent()->SectionIndex;
+ OS->Link = In.SymTab->getParent()->SectionIndex;
// sh_info then contain index of an entry in symbol table section which
// provides signature of the section group.
ObjFile<ELFT> *Obj = Section->getFile<ELFT>();
ArrayRef<Symbol *> Symbols = Obj->getSymbols();
- OS->Info = InX::SymTab->getSymbolIndex(Symbols[Section->Info]);
+ OS->Info = In.SymTab->getSymbolIndex(Symbols[Section->Info]);
}
template <class ELFT> void OutputSection::finalize() {
@@ -308,7 +310,7 @@ template <class ELFT> void OutputSection::finalize() {
if (isa<SyntheticSection>(First))
return;
- Link = InX::SymTab->getParent()->SectionIndex;
+ Link = In.SymTab->getParent()->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
InputSectionBase *S = First->getRelocatedSection();
@@ -406,12 +408,12 @@ void OutputSection::sortInitFini() {
sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
-uint32_t OutputSection::getFiller() {
+std::array<uint8_t, 4> OutputSection::getFiller() {
if (Filler)
return *Filler;
if (Flags & SHF_EXECINSTR)
return Target->TrapInstr;
- return 0;
+ return {0, 0, 0, 0};
}
template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index efb6aabe9743..113bf6836926 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -17,6 +17,7 @@
#include "lld/Common/LLVM.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
+#include <array>
namespace lld {
namespace elf {
@@ -94,7 +95,7 @@ public:
Expr SubalignExpr;
std::vector<BaseCommand *> SectionCommands;
std::vector<StringRef> Phdrs;
- llvm::Optional<uint32_t> Filler;
+ llvm::Optional<std::array<uint8_t, 4>> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
std::string MemoryRegionName;
@@ -117,7 +118,7 @@ private:
std::vector<uint8_t> ZDebugHeader;
llvm::SmallVector<char, 1> CompressedData;
- uint32_t getFiller();
+ std::array<uint8_t, 4> getFiller();
};
int getPriority(StringRef S);
@@ -130,7 +131,6 @@ std::vector<InputSection *> getInputSections(OutputSection* OS);
struct Out {
static uint8_t First;
static PhdrEntry *TlsPhdr;
- static OutputSection *DebugInfo;
static OutputSection *ElfHeader;
static OutputSection *ProgramHeaders;
static OutputSection *PreinitArray;
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 467219ad0542..812468896f0d 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -50,6 +50,7 @@
#include "SyntheticSections.h"
#include "Target.h"
#include "Thunks.h"
+#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/SmallSet.h"
@@ -65,6 +66,14 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
+static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) {
+ for (BaseCommand *Base : Script->SectionCommands)
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+ if (Cmd->Sym == &Sym)
+ return Cmd->Location;
+ return None;
+}
+
// Construct a message in the following format.
//
// >>> defined in /home/alice/src/foo.o
@@ -72,8 +81,13 @@ using namespace lld::elf;
// >>> /home/alice/src/bar.o:(.text+0x1)
static std::string getLocation(InputSectionBase &S, const Symbol &Sym,
uint64_t Off) {
- std::string Msg =
- "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
+ std::string Msg = "\n>>> defined in ";
+ if (Sym.File)
+ Msg += toString(Sym.File);
+ else if (Optional<std::string> Loc = getLinkerScriptLocation(Sym))
+ Msg += *Loc;
+
+ Msg += "\n>>> referenced by ";
std::string Src = S.getSrcMsg(Sym, Off);
if (!Src.empty())
Msg += Src + "\n>>> ";
@@ -90,12 +104,12 @@ static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
InputSectionBase &C, uint64_t Offset,
int64_t Addend, RelExpr Expr) {
if (Expr == R_MIPS_TLSLD) {
- InX::MipsGot->addTlsIndex(*C.File);
+ In.MipsGot->addTlsIndex(*C.File);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
if (Expr == R_MIPS_TLSGD) {
- InX::MipsGot->addDynTlsEntry(*C.File, Sym);
+ In.MipsGot->addDynTlsEntry(*C.File, Sym);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -128,17 +142,17 @@ 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, Dest);
+ In.RelaDyn->addReloc(Type, In.Got, Off, Dest);
else
- InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
+ In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
// Local Dynamic is for access to module local TLS variables, while still
// being suitable for being dynamically loaded via dlopen.
// GOT[e0] is the module index, with a special value of 0 for the current
// module. GOT[e1] is unused. There only needs to be one module index entry.
- if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) {
- AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) {
+ AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
NeedDynId ? nullptr : &Sym, NeedDynId);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
@@ -148,8 +162,8 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym,
// the module index and offset of symbol in TLS block we can fill these in
// using static GOT relocations.
if (Expr == R_TLSGD_PC) {
- if (InX::Got->addDynTlsEntry(Sym)) {
- uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId);
AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym,
NeedDynOff);
@@ -165,9 +179,6 @@ template <class ELFT>
static unsigned
handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
- if (!(C.Flags & SHF_ALLOC))
- return 0;
-
if (!Sym.isTls())
return 0;
@@ -176,12 +187,12 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (Config->EMachine == EM_MIPS)
return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr);
- if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
+ if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
- if (InX::Got->addDynTlsEntry(Sym)) {
- uint64_t Off = InX::Got->getGlobalDynOffset(Sym);
- InX::RelaDyn->addReloc(
- {Target->TlsDescRel, InX::Got, Off, !Sym.IsPreemptible, &Sym, 0});
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(
+ {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0});
}
if (Expr != R_TLSDESC_CALL)
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
@@ -199,9 +210,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
}
if (Expr == R_TLSLD_HINT)
return 1;
- if (InX::Got->addTlsIndex())
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got,
- InX::Got->getTlsIndexOff(), nullptr);
+ if (In.Got->addTlsIndex())
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got,
+ In.Got->getTlsIndexOff(), nullptr);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return 1;
}
@@ -223,29 +234,29 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
if (!Sym.isInGot()) {
- InX::Got->addEntry(Sym);
+ In.Got->addEntry(Sym);
uint64_t Off = Sym.getGotOffset();
- InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym});
+ In.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 (isRelExprOneOf<R_TLSDESC, R_AARCH64_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, &Sym);
+ if (In.Got->addDynTlsEntry(Sym)) {
+ uint64_t Off = In.Got->getGlobalDynOffset(Sym);
+ In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.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,
- &Sym);
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym);
else
- InX::Got->Relocations.push_back(
+ In.Got->Relocations.push_back(
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym});
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
@@ -259,9 +270,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type,
Offset, Addend, &Sym});
if (!Sym.isInGot()) {
- InX::Got->addEntry(Sym);
- InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(),
- &Sym);
+ In.Got->addEntry(Sym);
+ In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(),
+ &Sym);
}
} else {
C.Relocations.push_back(
@@ -273,13 +284,14 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
// Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
// defined.
- if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) &&
+ if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_AARCH64_GOT_PAGE_PC,
+ R_GOT_OFF, R_TLSIE_HINT>(Expr) &&
!Config->Shared && !Sym.IsPreemptible) {
C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym});
return 1;
}
- if (Expr == R_TLSDESC_CALL)
+ if (Expr == R_TLSIE_HINT)
return 1;
return 0;
}
@@ -325,23 +337,25 @@ 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_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
+ R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
}
// Returns true if Expr refers a GOT entry. Note that this function
// returns false for TLS variables even though they need GOT, because
// TLS variables uses GOT differently than the regular variables.
static bool needsGot(RelExpr Expr) {
- return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_GOT_PAGE_PC, R_GOT_PC,
- R_GOT_FROM_END>(Expr);
+ return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
+ R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
+ R_GOT_PLT>(Expr);
}
// True if this expression is of the form Sym - X, where X is a position in the
// file (PC, or GOT for example).
static bool isRelExpr(RelExpr Expr) {
return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
- R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC,
+ R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
R_RELAX_GOT_PC>(Expr);
}
@@ -357,18 +371,19 @@ 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_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))
+ if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, 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_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, 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_AARCH64_TLSDESC_PAGE, R_HINT,
+ R_TLSLD_HINT, R_TLSIE_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
// only the low bits are used.
- if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+ if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC)
return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
if (Sym.IsPreemptible)
@@ -414,10 +429,14 @@ static RelExpr toPlt(RelExpr Expr) {
return R_PPC_CALL_PLT;
case R_PC:
return R_PLT_PC;
- case R_PAGE_PC:
- return R_PLT_PAGE_PC;
+ case R_AARCH64_PAGE_PC:
+ return R_AARCH64_PLT_PAGE_PC;
+ case R_AARCH64_GOT_PAGE_PC:
+ return R_AARCH64_GOT_PAGE_PC_PLT;
case R_ABS:
return R_PLT;
+ case R_GOT:
+ return R_GOT_PLT;
default:
return Expr;
}
@@ -466,7 +485,7 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) {
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.getType() == STT_TLS || S.st_value != SS.Value)
continue;
StringRef Name = check(S.getName(File.getStringTable()));
Symbol *Sym = Symtab->find(Name);
@@ -489,6 +508,7 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value,
Sym.PltIndex = Old.PltIndex;
Sym.GotIndex = Old.GotIndex;
Sym.VerdefIndex = Old.VerdefIndex;
+ Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex;
Sym.IsPreemptible = true;
Sym.ExportDynamic = true;
Sym.IsUsedInRegularObj = true;
@@ -549,9 +569,9 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss",
SymSize, SS.Alignment);
if (IsReadOnly)
- InX::BssRelRo->getParent()->addSection(Sec);
+ In.BssRelRo->getParent()->addSection(Sec);
else
- InX::Bss->getParent()->addSection(Sec);
+ In.Bss->getParent()->addSection(Sec);
// 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
@@ -559,7 +579,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) {
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS))
replaceWithDefined(*Sym, Sec, 0, Sym->Size);
- InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
+ In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS);
}
// MIPS has an odd notion of "paired" relocations to calculate addends.
@@ -583,7 +603,7 @@ static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End,
if (PairTy == R_MIPS_NONE)
return 0;
- const uint8_t *Buf = Sec.Data.data();
+ const uint8_t *Buf = Sec.data().data();
uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
// To make things worse, paired relocations might not be contiguous in
@@ -611,7 +631,7 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End,
if (RelTy::IsRela) {
Addend = getAddend<ELFT>(Rel);
} else {
- const uint8_t *Buf = Sec.Data.data();
+ const uint8_t *Buf = Sec.data().data();
Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type);
}
@@ -627,9 +647,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End,
// Returns true if this function printed out an error message.
static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
uint64_t Offset) {
- if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
- return false;
-
if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak())
return false;
@@ -646,6 +663,10 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec,
Msg += Src + "\n>>> ";
Msg += Sec.getObjMsg(Offset);
+ if (Sym.getName().startswith("_ZTV"))
+ Msg += "\nthe vtable symbol may be undefined because the class is missing "
+ "its key function (see https://lld.llvm.org/missingkeyfunction)";
+
if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) ||
Config->NoinhibitExec) {
warn(Msg);
@@ -700,7 +721,7 @@ public:
while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off)
++I;
if (I == Pieces.size())
- return Off;
+ fatal(".eh_frame: relocation is not in any piece");
// Pieces must be contiguous, so there must be no holes in between.
assert(Pieces[I].InputOff <= Off && "Relocation not in any piece");
@@ -726,13 +747,13 @@ static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec,
// 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) {
+ if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) {
IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym});
- InX::RelrDyn->Relocs.push_back({IS, OffsetInSec});
+ In.RelrDyn->Relocs.push_back({IS, OffsetInSec});
return;
}
- InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend,
- Expr, Type);
+ In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr,
+ Type);
}
template <class ELFT, class GotPltSection>
@@ -745,9 +766,16 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
}
template <class ELFT> static void addGotEntry(Symbol &Sym) {
- InX::Got->addEntry(Sym);
+ In.Got->addEntry(Sym);
+
+ RelExpr Expr;
+ if (Sym.isTls())
+ Expr = R_TLS;
+ else if (Sym.isGnuIFunc())
+ Expr = R_PLT;
+ else
+ Expr = R_ABS;
- RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
uint64_t Off = Sym.getGotOffset();
// If a GOT slot value can be calculated at link-time, which is now,
@@ -760,19 +788,19 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) {
bool IsLinkTimeConstant =
!Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym));
if (IsLinkTimeConstant) {
- InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
+ In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym});
return;
}
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that
// the GOT slot will be fixed at load-time.
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) {
- addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel);
+ addRelativeReloc(In.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);
+ In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got,
+ Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS,
+ Target->GotRel);
}
// Return true if we can define a symbol in the executable that
@@ -825,7 +853,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
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);
+ In.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
@@ -843,7 +871,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
// 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(*Sec.File, Sym, Addend, Expr);
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
return;
}
}
@@ -930,10 +958,9 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
"' cannot be preempted; recompile with -fPIE" +
getLocation(Sec, Sym, Offset));
if (!Sym.isInPlt())
- addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel,
- Sym);
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
if (!Sym.isDefined())
- replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0);
+ replaceWithDefined(Sym, In.Plt, getPltEntryOffset(Sym.PltIndex), 0);
Sym.NeedsPltAddr = true;
Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
return;
@@ -967,7 +994,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
if (maybeReportUndefined(Sym, Sec, Rel.r_offset))
return;
- const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset;
+ 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.
@@ -985,18 +1012,28 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// 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())
+ if (Sym.isGnuIFunc()) {
+ if (!Config->ZText && Config->WarnIfuncTextrel) {
+ warn("using ifunc symbols when text relocations are allowed may produce "
+ "a binary that will segfault, if the object file is linked with "
+ "old version of glibc (glibc 2.28 and earlier). If this applies to "
+ "you, consider recompiling the object files without -fPIC and "
+ "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
+ "turn off this warning." +
+ getLocation(Sec, Sym, Offset));
+ }
Expr = toPlt(Expr);
- else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) {
Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
- else if (!Sym.IsPreemptible)
+ } 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;
+ In.Got->HasGotOffRel = true;
// Read an addend.
int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal());
@@ -1012,11 +1049,10 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// 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,
+ addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
Sym);
+ else
+ addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
}
// Create a GOT slot if a relocation needs GOT.
@@ -1029,7 +1065,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
// 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);
+ In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
} else if (!Sym.isInGot()) {
addGotEntry<ELFT>(Sym);
}
@@ -1047,6 +1083,11 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
for (auto I = Rels.begin(), End = Rels.end(); I != End;)
scanReloc<ELFT>(Sec, GetOffset, I, End);
+
+ // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20
+ if (Config->EMachine == EM_RISCV)
+ std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(),
+ RelocationOffsetComparator{});
}
template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
@@ -1056,6 +1097,43 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
scanRelocs<ELFT>(S, S.rels<ELFT>());
}
+static bool mergeCmp(const InputSection *A, const InputSection *B) {
+ // std::merge requires a strict weak ordering.
+ if (A->OutSecOff < B->OutSecOff)
+ return true;
+
+ if (A->OutSecOff == B->OutSecOff) {
+ auto *TA = dyn_cast<ThunkSection>(A);
+ auto *TB = dyn_cast<ThunkSection>(B);
+
+ // Check if Thunk is immediately before any specific Target
+ // InputSection for example Mips LA25 Thunks.
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+
+ // Place Thunk Sections without specific targets before
+ // non-Thunk Sections.
+ if (TA && !TB && !TA->getTargetInputSection())
+ return true;
+ }
+
+ return false;
+}
+
+// Call Fn on every executable InputSection accessed via the linker script
+// InputSectionDescription::Sections.
+static void forEachInputSectionDescription(
+ ArrayRef<OutputSection *> OutputSections,
+ llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
+ for (OutputSection *OS : OutputSections) {
+ if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
+ continue;
+ for (BaseCommand *BC : OS->SectionCommands)
+ if (auto *ISD = dyn_cast<InputSectionDescription>(BC))
+ Fn(OS, ISD);
+ }
+}
+
// Thunk Implementation
//
// Thunks (sometimes called stubs, veneers or branch islands) are small pieces
@@ -1158,6 +1236,7 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
[](const std::pair<ThunkSection *, uint32_t> &TS) {
return TS.first->getSize() == 0;
});
+
// ISD->ThunkSections contains all created ThunkSections, including
// those inserted in previous passes. Extract the Thunks created this
// pass and order them in ascending OutSecOff.
@@ -1173,27 +1252,11 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) {
// Merge sorted vectors of Thunks and InputSections by OutSecOff
std::vector<InputSection *> Tmp;
Tmp.reserve(ISD->Sections.size() + NewThunks.size());
- auto MergeCmp = [](const InputSection *A, const InputSection *B) {
- // std::merge requires a strict weak ordering.
- if (A->OutSecOff < B->OutSecOff)
- return true;
- if (A->OutSecOff == B->OutSecOff) {
- auto *TA = dyn_cast<ThunkSection>(A);
- auto *TB = dyn_cast<ThunkSection>(B);
- // Check if Thunk is immediately before any specific Target
- // InputSection for example Mips LA25 Thunks.
- if (TA && TA->getTargetInputSection() == B)
- return true;
- if (TA && !TB && !TA->getTargetInputSection())
- // Place Thunk Sections without specific targets before
- // non-Thunk Sections.
- return true;
- }
- return false;
- };
+
std::merge(ISD->Sections.begin(), ISD->Sections.end(),
NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp),
- MergeCmp);
+ mergeCmp);
+
ISD->Sections = std::move(Tmp);
});
}
@@ -1237,20 +1300,23 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
// Find InputSectionRange within Target Output Section (TOS) that the
// InputSection (IS) that we need to precede is in.
OutputSection *TOS = IS->getParent();
- for (BaseCommand *BC : TOS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) {
- if (ISD->Sections.empty())
- continue;
- InputSection *first = ISD->Sections.front();
- InputSection *last = ISD->Sections.back();
- if (IS->OutSecOff >= first->OutSecOff &&
- IS->OutSecOff <= last->OutSecOff) {
- TS = addThunkSection(TOS, ISD, IS->OutSecOff);
- ThunkedSections[IS] = TS;
- break;
- }
- }
- return TS;
+ for (BaseCommand *BC : TOS->SectionCommands) {
+ auto *ISD = dyn_cast<InputSectionDescription>(BC);
+ if (!ISD || ISD->Sections.empty())
+ continue;
+
+ InputSection *First = ISD->Sections.front();
+ InputSection *Last = ISD->Sections.back();
+
+ if (IS->OutSecOff < First->OutSecOff || Last->OutSecOff < IS->OutSecOff)
+ continue;
+
+ TS = addThunkSection(TOS, ISD, IS->OutSecOff);
+ ThunkedSections[IS] = TS;
+ return TS;
+ }
+
+ return nullptr;
}
// Create one or more ThunkSections per OS that can be used to place Thunks.
@@ -1271,26 +1337,29 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) {
// allow for the creation of a short thunk.
void ThunkCreator::createInitialThunkSections(
ArrayRef<OutputSection *> OutputSections) {
+ uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing();
+
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;
+ if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2)
+ LastThunkLowerBound = ISDEnd - ThunkSectionSpacing;
uint32_t ISLimit;
uint32_t PrevISLimit = ISDBegin;
- uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing;
+ uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing;
for (const InputSection *IS : ISD->Sections) {
ISLimit = IS->OutSecOff + IS->getSize();
if (ISLimit > ThunkUpperBound) {
addThunkSection(OS, ISD, PrevISLimit);
- ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing;
+ ThunkUpperBound = PrevISLimit + ThunkSectionSpacing;
}
if (ISLimit > LastThunkLowerBound)
break;
@@ -1304,13 +1373,14 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS,
InputSectionDescription *ISD,
uint64_t Off) {
auto *TS = make<ThunkSection>(OS, Off);
- ISD->ThunkSections.push_back(std::make_pair(TS, Pass));
+ ISD->ThunkSections.push_back({TS, Pass});
return TS;
}
std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
uint64_t Src) {
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))
@@ -1318,40 +1388,28 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type,
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);
+ for (Thunk *T : *ThunkVec)
+ if (T->isCompatibleWith(Type) &&
+ Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA()))
+ return std::make_pair(T, false);
+
// No existing compatible Thunk in range, create a new one
Thunk *T = addThunk(Type, Sym);
ThunkVec->push_back(T);
return std::make_pair(T, true);
}
-// Call Fn on every executable InputSection accessed via the linker script
-// InputSectionDescription::Sections.
-void ThunkCreator::forEachInputSectionDescription(
- ArrayRef<OutputSection *> OutputSections,
- llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) {
- for (OutputSection *OS : OutputSections) {
- if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR))
- continue;
- for (BaseCommand *BC : OS->SectionCommands)
- if (auto *ISD = dyn_cast<InputSectionDescription>(BC))
- Fn(OS, ISD);
- }
-}
-
// Return true if the relocation target is an in range Thunk.
// Return false if the relocation is not to a Thunk. If the relocation target
// was originally to a Thunk, but is no longer in range we revert the
// relocation back to its original non-Thunk target.
bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) {
- if (Thunk *ET = Thunks.lookup(Rel.Sym)) {
+ if (Thunk *T = Thunks.lookup(Rel.Sym)) {
if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA()))
return true;
- Rel.Sym = &ET->Destination;
+ Rel.Sym = &T->Destination;
if (Rel.Sym->isInPlt())
Rel.Expr = toPlt(Rel.Expr);
}
@@ -1385,11 +1443,13 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) {
// relocation out of range error.
bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
bool AddressesChanged = false;
- if (Pass == 0 && Target->ThunkSectionSpacing)
+
+ if (Pass == 0 && Target->getThunkSectionSpacing())
createInitialThunkSections(OutputSections);
- else if (Pass == 10)
- // With Thunk Size much smaller than branch range we expect to
- // converge quickly; if we get to 10 something has gone wrong.
+
+ // With Thunk Size much smaller than branch range we expect to
+ // converge quickly; if we get to 10 something has gone wrong.
+ if (Pass == 10)
fatal("thunk creation not converged");
// Create all the Thunks and insert them into synthetic ThunkSections. The
@@ -1412,9 +1472,11 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src,
*Rel.Sym))
continue;
+
Thunk *T;
bool IsNew;
std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src);
+
if (IsNew) {
// Find or create a ThunkSection for the new Thunk
ThunkSection *TS;
@@ -1425,13 +1487,16 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) {
TS->addThunk(T);
Thunks[T->getThunkTargetSym()] = T;
}
+
// Redirect relocation to Thunk, we never go via the PLT to a Thunk
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();
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index a4125111c4fe..d00e68bd36e6 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -33,16 +33,28 @@ enum RelExpr {
R_INVALID,
R_ABS,
R_ADDEND,
+ R_AARCH64_GOT_PAGE_PC,
+ // The expression is used for IFUNC support. Describes PC-relative
+ // address of the memory page of GOT entry. This entry is used for
+ // a redirection to IPLT.
+ R_AARCH64_GOT_PAGE_PC_PLT,
+ R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
+ R_AARCH64_PAGE_PC,
+ R_AARCH64_PLT_PAGE_PC,
+ R_AARCH64_TLSDESC_PAGE,
R_ARM_SBREL,
R_GOT,
+ // The expression is used for IFUNC support. Evaluates to GOT entry,
+ // containing redirection to the IPLT.
+ R_GOT_PLT,
R_GOTONLY_PC,
R_GOTONLY_PC_FROM_END,
R_GOTREL,
R_GOTREL_FROM_END,
R_GOT_FROM_END,
R_GOT_OFF,
- R_GOT_PAGE_PC,
R_GOT_PC,
+ R_HEXAGON_GOT,
R_HINT,
R_MIPS_GOTREL,
R_MIPS_GOT_GP,
@@ -54,10 +66,8 @@ enum RelExpr {
R_MIPS_TLSLD,
R_NEG_TLS,
R_NONE,
- R_PAGE_PC,
R_PC,
R_PLT,
- R_PLT_PAGE_PC,
R_PLT_PC,
R_PPC_CALL,
R_PPC_CALL_PLT,
@@ -68,20 +78,20 @@ enum RelExpr {
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_RISCV_PC_INDIRECT,
R_SIZE,
R_TLS,
R_TLSDESC,
R_TLSDESC_CALL,
- R_TLSDESC_PAGE,
R_TLSGD_GOT,
R_TLSGD_GOT_FROM_END,
R_TLSGD_PC,
+ R_TLSIE_HINT,
R_TLSLD_GOT,
R_TLSLD_GOT_FROM_END,
R_TLSLD_GOT_OFF,
@@ -128,6 +138,21 @@ struct Relocation {
Symbol *Sym;
};
+struct RelocationOffsetComparator {
+ bool operator()(const Relocation &Lhs, const Relocation &Rhs) {
+ return Lhs.Offset < Rhs.Offset;
+ }
+
+ // For std::lower_bound, std::upper_bound, std::equal_range.
+ bool operator()(const Relocation &Rel, uint64_t Val) {
+ return Rel.Offset < Val;
+ }
+
+ bool operator()(uint64_t Val, const Relocation &Rel) {
+ return Val < Rel.Offset;
+ }
+};
+
template <class ELFT> void scanRelocations(InputSectionBase &);
class ThunkSection;
@@ -155,10 +180,6 @@ private:
void createInitialThunkSections(ArrayRef<OutputSection *> OutputSections);
- void forEachInputSectionDescription(
- ArrayRef<OutputSection *> OutputSections,
- llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn);
-
std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src);
ThunkSection *addThunkSection(OutputSection *OS, InputSectionDescription *,
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
index d4b1f6d99cc1..9a372c6d1c6f 100644
--- a/ELF/ScriptLexer.cpp
+++ b/ELF/ScriptLexer.cpp
@@ -244,6 +244,15 @@ StringRef ScriptLexer::peek() {
return Tok;
}
+StringRef ScriptLexer::peek2() {
+ skip();
+ StringRef Tok = next();
+ if (errorCount())
+ return "";
+ Pos = Pos - 2;
+ return Tok;
+}
+
bool ScriptLexer::consume(StringRef Tok) {
if (peek() == Tok) {
skip();
diff --git a/ELF/ScriptLexer.h b/ELF/ScriptLexer.h
index e7c8b28e49fd..fc6b5b1008a7 100644
--- a/ELF/ScriptLexer.h
+++ b/ELF/ScriptLexer.h
@@ -29,6 +29,7 @@ public:
bool atEOF();
StringRef next();
StringRef peek();
+ StringRef peek2();
void skip();
bool consume(StringRef Tok);
void expect(StringRef Expect);
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index ddb4a49a3e5e..eee3f0e330cc 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -72,13 +72,15 @@ private:
void readRegionAlias();
void readSearchDir();
void readSections();
+ void readTarget();
void readVersion();
void readVersionScriptCommand();
SymbolAssignment *readSymbolAssignment(StringRef Name);
ByteCommand *readByteCommand(StringRef Tok);
- uint32_t readFill();
- uint32_t parseFill(StringRef Tok);
+ std::array<uint8_t, 4> readFill();
+ std::array<uint8_t, 4> parseFill(StringRef Tok);
+ bool readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2);
void readSectionAddressType(OutputSection *Cmd);
OutputSection *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef OutSec);
@@ -92,6 +94,7 @@ private:
SortSectionPolicy readSortKind();
SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
SymbolAssignment *readAssignment(StringRef Tok);
+ std::tuple<ELFKind, uint16_t, bool> readBfdName();
void readSort();
Expr readAssert();
Expr readConstant();
@@ -255,6 +258,8 @@ void ScriptParser::readLinkerScript() {
readSearchDir();
} else if (Tok == "SECTIONS") {
readSections();
+ } else if (Tok == "TARGET") {
+ readTarget();
} else if (Tok == "VERSION") {
readVersion();
} else if (SymbolAssignment *Cmd = readAssignment(Tok)) {
@@ -266,6 +271,8 @@ void ScriptParser::readLinkerScript() {
}
void ScriptParser::readDefsym(StringRef Name) {
+ if (errorCount())
+ return;
Expr E = readExpr();
if (!atEOF())
setError("EOF expected, but got " + next());
@@ -378,10 +385,50 @@ void ScriptParser::readOutputArch() {
skip();
}
+std::tuple<ELFKind, uint16_t, bool> ScriptParser::readBfdName() {
+ StringRef S = unquote(next());
+ if (S == "elf32-i386")
+ return std::make_tuple(ELF32LEKind, EM_386, false);
+ if (S == "elf32-iamcu")
+ return std::make_tuple(ELF32LEKind, EM_IAMCU, false);
+ if (S == "elf32-littlearm")
+ return std::make_tuple(ELF32LEKind, EM_ARM, false);
+ if (S == "elf32-x86-64")
+ return std::make_tuple(ELF32LEKind, EM_X86_64, false);
+ if (S == "elf64-littleaarch64")
+ return std::make_tuple(ELF64LEKind, EM_AARCH64, false);
+ if (S == "elf64-powerpc")
+ return std::make_tuple(ELF64BEKind, EM_PPC64, false);
+ if (S == "elf64-powerpcle")
+ return std::make_tuple(ELF64LEKind, EM_PPC64, false);
+ if (S == "elf64-x86-64")
+ return std::make_tuple(ELF64LEKind, EM_X86_64, false);
+ if (S == "elf32-tradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, false);
+ if (S == "elf32-ntradbigmips")
+ return std::make_tuple(ELF32BEKind, EM_MIPS, true);
+ if (S == "elf32-tradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, false);
+ if (S == "elf32-ntradlittlemips")
+ return std::make_tuple(ELF32LEKind, EM_MIPS, true);
+ if (S == "elf64-tradbigmips")
+ return std::make_tuple(ELF64BEKind, EM_MIPS, false);
+ if (S == "elf64-tradlittlemips")
+ return std::make_tuple(ELF64LEKind, EM_MIPS, false);
+
+ setError("unknown output format name: " + S);
+ return std::make_tuple(ELFNoneKind, EM_NONE, false);
+}
+
+// Parse OUTPUT_FORMAT(bfdname) or OUTPUT_FORMAT(bfdname, big, little).
+// Currently we ignore big and little parameters.
void ScriptParser::readOutputFormat() {
- // Error checking only for now.
expect("(");
- skip();
+
+ std::tuple<ELFKind, uint16_t, bool> BfdTuple = readBfdName();
+ if (Config->EKind == ELFNoneKind)
+ std::tie(Config->EKind, Config->EMachine, Config->MipsN32Abi) = BfdTuple;
+
if (consume(")"))
return;
expect(",");
@@ -497,6 +544,9 @@ void ScriptParser::readSections() {
for (BaseCommand *Cmd : readOverlay())
V.push_back(Cmd);
continue;
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
}
if (BaseCommand *Cmd = readAssignment(Tok))
@@ -522,6 +572,23 @@ void ScriptParser::readSections() {
V.end());
}
+void ScriptParser::readTarget() {
+ // TARGET(foo) is an alias for "--format foo". Unlike GNU linkers,
+ // we accept only a limited set of BFD names (i.e. "elf" or "binary")
+ // for --format. We recognize only /^elf/ and "binary" in the linker
+ // script as well.
+ expect("(");
+ StringRef Tok = next();
+ expect(")");
+
+ if (Tok.startswith("elf"))
+ Config->FormatBinary = false;
+ else if (Tok == "binary")
+ Config->FormatBinary = true;
+ else
+ setError("unknown target: " + Tok);
+}
+
static int precedence(StringRef Op) {
return StringSwitch<int>(Op)
.Cases("*", "/", "%", 8)
@@ -672,13 +739,33 @@ Expr ScriptParser::readAssert() {
// alias for =fillexp section attribute, which is different from
// what GNU linkers do.
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
-uint32_t ScriptParser::readFill() {
+std::array<uint8_t, 4> ScriptParser::readFill() {
expect("(");
- uint32_t V = parseFill(next());
+ std::array<uint8_t, 4> V = parseFill(next());
expect(")");
return V;
}
+// Tries to read the special directive for an output section definition which
+// can be one of following: "(NOLOAD)", "(COPY)", "(INFO)" or "(OVERLAY)".
+// Tok1 and Tok2 are next 2 tokens peeked. See comment for readSectionAddressType below.
+bool ScriptParser::readSectionDirective(OutputSection *Cmd, StringRef Tok1, StringRef Tok2) {
+ if (Tok1 != "(")
+ return false;
+ if (Tok2 != "NOLOAD" && Tok2 != "COPY" && Tok2 != "INFO" && Tok2 != "OVERLAY")
+ return false;
+
+ expect("(");
+ if (consume("NOLOAD")) {
+ Cmd->Noload = true;
+ } else {
+ skip(); // This is "COPY", "INFO" or "OVERLAY".
+ Cmd->NonAlloc = true;
+ }
+ expect(")");
+ return true;
+}
+
// Reads an expression and/or the special directive for an output
// section definition. Directive is one of following: "(NOLOAD)",
// "(COPY)", "(INFO)" or "(OVERLAY)".
@@ -691,28 +778,12 @@ uint32_t ScriptParser::readFill() {
// https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
// https://sourceware.org/binutils/docs/ld/Output-Section-Type.html
void ScriptParser::readSectionAddressType(OutputSection *Cmd) {
- if (consume("(")) {
- if (consume("NOLOAD")) {
- expect(")");
- Cmd->Noload = true;
- return;
- }
- if (consume("COPY") || consume("INFO") || consume("OVERLAY")) {
- expect(")");
- Cmd->NonAlloc = true;
- return;
- }
- Cmd->AddrExpr = readExpr();
- expect(")");
- } else {
- Cmd->AddrExpr = readExpr();
- }
+ if (readSectionDirective(Cmd, peek(), peek2()))
+ return;
- if (consume("(")) {
- expect("NOLOAD");
- expect(")");
- Cmd->Noload = true;
- }
+ Cmd->AddrExpr = readExpr();
+ if (peek() == "(" && !readSectionDirective(Cmd, "(", peek2()))
+ setError("unknown section directive: " + peek2());
}
static Expr checkAlignment(Expr E, std::string &Loc) {
@@ -778,10 +849,17 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
Cmd->Filler = readFill();
} else if (Tok == "SORT") {
readSort();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
} else if (peek() == "(") {
Cmd->SectionCommands.push_back(readInputSectionDescription(Tok));
} else {
- setError("unknown command " + Tok);
+ // We have a file name and no input sections description. It is not a
+ // commonly used syntax, but still acceptable. In that case, all sections
+ // from the file will be included.
+ auto *ISD = make<InputSectionDescription>(Tok);
+ ISD->SectionPatterns.push_back({{}, StringMatcher({"*"})});
+ Cmd->SectionCommands.push_back(ISD);
}
}
@@ -818,13 +896,13 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) {
// When reading a hexstring, ld.bfd handles it as a blob of arbitrary
// size, while ld.gold always handles it as a 32-bit big-endian number.
// We are compatible with ld.gold because it's easier to implement.
-uint32_t ScriptParser::parseFill(StringRef Tok) {
+std::array<uint8_t, 4> ScriptParser::parseFill(StringRef Tok) {
uint32_t V = 0;
if (!to_integer(Tok, V))
setError("invalid filler expression: " + Tok);
- uint32_t Buf;
- write32be(&Buf, V);
+ std::array<uint8_t, 4> Buf;
+ write32be(Buf.data(), V);
return Buf;
}
@@ -1404,7 +1482,11 @@ uint64_t ScriptParser::readMemoryAssignment(StringRef S1, StringRef S2,
void ScriptParser::readMemory() {
expect("{");
while (!errorCount() && !consume("}")) {
- StringRef Name = next();
+ StringRef Tok = next();
+ if (Tok == "INCLUDE") {
+ readInclude();
+ continue;
+ }
uint32_t Flags = 0;
uint32_t NegFlags = 0;
@@ -1419,10 +1501,9 @@ void ScriptParser::readMemory() {
uint64_t Length = readMemoryAssignment("LENGTH", "len", "l");
// Add the memory region to the region map.
- 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>(Tok, Origin, Length, Flags, NegFlags);
+ if (!Script->MemoryRegions.insert({Tok, MR}).second)
+ setError("region '" + Tok + "' already defined");
}
}
diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp
index 1f5a84ec2c7d..7615e12199fa 100644
--- a/ELF/SymbolTable.cpp
+++ b/ELF/SymbolTable.cpp
@@ -94,8 +94,20 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) {
if (auto *F = dyn_cast<SharedFile<ELFT>>(File)) {
// DSOs are uniquified not by filename but by soname.
F->parseSoName();
- if (errorCount() || !SoNames.insert(F->SoName).second)
+ if (errorCount())
return;
+
+ // If a DSO appears more than once on the command line with and without
+ // --as-needed, --no-as-needed takes precedence over --as-needed because a
+ // user can add an extra DSO with --no-as-needed to force it to be added to
+ // the dependency list.
+ DenseMap<StringRef, InputFile *>::iterator It;
+ bool WasInserted;
+ std::tie(It, WasInserted) = SoNames.try_emplace(F->SoName, F);
+ cast<SharedFile<ELFT>>(It->second)->IsNeeded |= F->IsNeeded;
+ if (!WasInserted)
+ return;
+
SharedFiles.push_back(F);
F->parseRest();
return;
@@ -139,77 +151,27 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() {
}
}
-Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility,
- uint8_t Binding) {
- Symbol *Sym =
- addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr);
- return cast<Defined>(Sym);
-}
-
// Set a flag for --trace-symbol so that we can print out a log message
// if a new symbol with the same name is inserted into the symbol table.
void SymbolTable::trace(StringRef Name) {
SymMap.insert({CachedHashStringRef(Name), -1});
}
-// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
-// Used to implement --wrap.
-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;
+void SymbolTable::wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap) {
+ // Swap symbols as instructed by -wrap.
+ int &Idx1 = SymMap[CachedHashStringRef(Sym->getName())];
+ int &Idx2 = SymMap[CachedHashStringRef(Real->getName())];
+ int &Idx3 = SymMap[CachedHashStringRef(Wrap->getName())];
- Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name));
- Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name));
- WrappedSymbols.push_back({Sym, Real, Wrap});
+ Idx2 = Idx1;
+ Idx1 = Idx3;
- // We want to tell LTO not to inline symbols to be overwritten
- // because LTO doesn't know the final symbol contents after renaming.
- Real->CanInline = false;
- Sym->CanInline = false;
-
- // Tell LTO not to eliminate these symbols.
- Sym->IsUsedInRegularObj = true;
- Wrap->IsUsedInRegularObj = true;
-}
-
-// Apply symbol renames created by -wrap. The renames are created
-// before LTO in addSymbolWrap() to have a chance to inform LTO (if
-// LTO is running) not to include these symbols in IPO. Now that the
-// symbols are finalized, we can perform the replacement.
-void SymbolTable::applySymbolWrap() {
- // This function rotates 3 symbols:
- //
- // __real_sym becomes sym
- // sym becomes __wrap_sym
- // __wrap_sym becomes __real_sym
- //
- // The last part is special in that we don't want to change what references to
- // __wrap_sym point to, we just want have __real_sym in the symbol table.
-
- for (WrappedSymbol &W : WrappedSymbols) {
- // First, make a copy of __real_sym.
- Symbol *Real = nullptr;
- if (W.Real->isDefined()) {
- Real = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- memcpy(Real, W.Real, sizeof(SymbolUnion));
- }
-
- // Replace __real_sym with sym and sym with __wrap_sym.
- memcpy(W.Real, W.Sym, sizeof(SymbolUnion));
- memcpy(W.Sym, W.Wrap, sizeof(SymbolUnion));
-
- // We now have two copies of __wrap_sym. Drop one.
- W.Wrap->IsUsedInRegularObj = false;
-
- if (Real)
- SymVector.push_back(Real);
- }
+ // Now renaming is complete. No one refers Real symbol. We could leave
+ // Real as-is, but if Real is written to the symbol table, that may
+ // contain irrelevant values. So, we copy all values from Sym to Real.
+ StringRef S = Real->getName();
+ memcpy(Real, Sym, sizeof(SymbolUnion));
+ Real->setName(S);
}
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
@@ -221,7 +183,7 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
}
// Find an existing symbol or create and insert a new one.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+std::pair<Symbol *, bool> SymbolTable::insertName(StringRef Name) {
// <name>@@<version> means the symbol is the default version. In that
// case <name>@@<version> will be used to resolve references to <name>.
//
@@ -239,34 +201,34 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
if (SymIndex == -1) {
SymIndex = SymVector.size();
- IsNew = Traced = true;
+ IsNew = true;
+ Traced = true;
}
- Symbol *Sym;
- if (IsNew) {
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->Visibility = STV_DEFAULT;
- Sym->IsUsedInRegularObj = false;
- Sym->ExportDynamic = false;
- Sym->CanInline = true;
- Sym->Traced = Traced;
- Sym->VersionId = Config->DefaultSymbolVersion;
- SymVector.push_back(Sym);
- } else {
- Sym = SymVector[SymIndex];
- }
- return {Sym, IsNew};
+ if (!IsNew)
+ return {SymVector[SymIndex], false};
+
+ auto *Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->SymbolKind = Symbol::PlaceholderKind;
+ Sym->Visibility = STV_DEFAULT;
+ Sym->IsUsedInRegularObj = false;
+ Sym->ExportDynamic = false;
+ Sym->CanInline = true;
+ Sym->Traced = Traced;
+ Sym->VersionId = Config->DefaultSymbolVersion;
+ SymVector.push_back(Sym);
+ return {Sym, true};
}
// Find an existing symbol or create and insert a new one, then apply the given
// attributes.
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name,
uint8_t Visibility,
bool CanOmitFromDynSym,
InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
// Merge in the new symbol's visibility.
S->Visibility = getMinVisibility(S->Visibility, Visibility);
@@ -277,21 +239,9 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, uint8_t Type,
if (!File || File->kind() == InputFile::ObjKind)
S->IsUsedInRegularObj = true;
- if (!WasInserted && S->Type != Symbol::UnknownType &&
- ((Type == STT_TLS) != S->isTls())) {
- error("TLS attribute mismatch: " + toString(*S) + "\n>>> defined in " +
- toString(S->File) + "\n>>> defined in " + toString(File));
- }
-
return {S, WasInserted};
}
-template <class ELFT> Symbol *SymbolTable::addUndefined(StringRef Name) {
- return addUndefined<ELFT>(Name, STB_GLOBAL, STV_DEFAULT,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-}
-
static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; }
template <class ELFT>
@@ -301,8 +251,7 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
uint8_t Visibility = getVisibility(StOther);
- std::tie(S, WasInserted) =
- insert(Name, Type, Visibility, CanOmitFromDynSym, File);
+ std::tie(S, WasInserted) = insert(Name, Visibility, CanOmitFromDynSym, File);
// An undefined symbol with non default visibility must be satisfied
// in the same DSO.
@@ -314,10 +263,6 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding,
if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK))
S->Binding = Binding;
- if (!Config->GcSections && Binding != STB_WEAK)
- if (auto *SS = dyn_cast<SharedSymbol>(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.
@@ -450,7 +395,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
InputFile &File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther),
+ std::tie(S, WasInserted) = insert(N, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, &File);
int Cmp = compareDefined(S, WasInserted, Binding, N);
@@ -487,12 +432,6 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment,
return S;
}
-static void reportDuplicate(Symbol *Sym, InputFile *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, InputFile *NewFile,
InputSectionBase *ErrSec, uint64_t ErrOffset) {
if (Config->AllowMultipleDefinition)
@@ -500,7 +439,8 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
Defined *D = cast<Defined>(Sym);
if (!D->Section || !ErrSec) {
- reportDuplicate(Sym, NewFile);
+ error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " +
+ toString(Sym->File) + "\n>>> defined in " + toString(NewFile));
return;
}
@@ -527,12 +467,12 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile,
error(Msg);
}
-Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File) {
+Defined *SymbolTable::addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther),
+ std::tie(S, WasInserted) = insert(Name, getVisibility(StOther),
/*CanOmitFromDynSym*/ false, File);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr,
Value, Name);
@@ -542,7 +482,7 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
else if (Cmp == 0)
reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section),
Value);
- return S;
+ return cast<Defined>(S);
}
template <typename ELFT>
@@ -554,7 +494,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File,
// unchanged.
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT,
+ std::tie(S, WasInserted) = insert(Name, STV_DEFAULT,
/*CanOmitFromDynSym*/ true, &File);
// Make sure we preempt DSO symbols with default visibility.
if (Sym.getVisibility() == STV_DEFAULT)
@@ -562,19 +502,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->Visibility == STV_DEFAULT)) {
- uint8_t Binding = S->Binding;
- bool WasUndefined = S->isUndefined();
- replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other,
+ auto Replace = [&](uint8_t Binding) {
+ replaceSymbol<SharedSymbol>(S, File, Name, Binding, Sym.st_other,
Sym.getType(), Sym.st_value, Sym.st_size,
Alignment, VerdefIndex);
- if (!WasInserted) {
- S->Binding = Binding;
- if (!S->isWeak() && !Config->GcSections && WasUndefined)
- File.IsNeeded = true;
- }
- }
+ };
+
+ if (WasInserted)
+ Replace(Sym.getBinding());
+ else if (S->Visibility == STV_DEFAULT && (S->isUndefined() || S->isLazy()))
+ Replace(S->Binding);
}
Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
@@ -583,13 +520,13 @@ Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) =
- insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F);
+ insert(Name, getVisibility(StOther), CanOmitFromDynSym, &F);
int Cmp = compareDefinedNonCommon(S, WasInserted, Binding,
/*IsAbs*/ false, /*Value*/ 0, Name);
if (Cmp > 0)
replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr);
else if (Cmp == 0)
- reportDuplicate(S, &F);
+ reportDuplicate(S, &F, nullptr, 0);
return S;
}
@@ -602,18 +539,14 @@ Symbol *SymbolTable::find(StringRef Name) {
return SymVector[It->second];
}
-// 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) {
+template <class ELFT>
+void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &File,
+ const object::Archive::Symbol Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = Symtab->insert(Name);
+ std::tie(S, WasInserted) = insertName(Name);
if (WasInserted) {
- replaceSymbol<LazyT>(S, File, Symbol::UnknownType,
- std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, STT_NOTYPE, Sym);
return;
}
if (!S->isUndefined())
@@ -622,26 +555,37 @@ static void replaceOrFetchLazy(StringRef Name, InputFile &File,
// An undefined weak will not fetch archive members. See comment on Lazy in
// Symbols.h for the details.
if (S->isWeak()) {
- replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...);
+ replaceSymbol<LazyArchive>(S, File, S->Type, Sym);
S->Binding = STB_WEAK;
return;
}
- if (InputFile *F = Fetch())
- Symtab->addFile<ELFT>(F);
+ if (InputFile *F = File.fetch(Sym))
+ addFile<ELFT>(F);
}
template <class ELFT>
-void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F,
- const object::Archive::Symbol Sym) {
- replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); },
- Sym);
-}
+void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &File) {
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insertName(Name);
+ if (WasInserted) {
+ replaceSymbol<LazyObject>(S, File, STT_NOTYPE, Name);
+ return;
+ }
+ if (!S->isUndefined())
+ return;
-template <class ELFT>
-void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) {
- replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); },
- Name);
+ // An undefined weak will not fetch archive members. See comment on Lazy in
+ // Symbols.h for the details.
+ if (S->isWeak()) {
+ replaceSymbol<LazyObject>(S, File, S->Type, Name);
+ S->Binding = STB_WEAK;
+ return;
+ }
+
+ if (InputFile *F = File.fetch())
+ addFile<ELFT>(F);
}
template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) {
@@ -822,16 +766,6 @@ 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);
-template void SymbolTable::addSymbolWrap<ELF64BE>(StringRef);
-
-template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64LE>(StringRef);
-template Symbol *SymbolTable::addUndefined<ELF64BE>(StringRef);
-
template Symbol *SymbolTable::addUndefined<ELF32LE>(StringRef, uint8_t, uint8_t,
uint8_t, bool, InputFile *);
template Symbol *SymbolTable::addUndefined<ELF32BE>(StringRef, uint8_t, uint8_t,
diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h
index 5e6d44dfe4f9..898185fc9612 100644
--- a/ELF/SymbolTable.h
+++ b/ELF/SymbolTable.h
@@ -37,22 +37,17 @@ class SymbolTable {
public:
template <class ELFT> void addFile(InputFile *File);
template <class ELFT> void addCombinedLTOObject();
- template <class ELFT> void addSymbolWrap(StringRef Name);
- void applySymbolWrap();
+ void wrap(Symbol *Sym, Symbol *Real, Symbol *Wrap);
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
- Defined *addAbsolute(StringRef Name,
- uint8_t Visibility = llvm::ELF::STV_HIDDEN,
- uint8_t Binding = llvm::ELF::STB_GLOBAL);
-
- template <class ELFT> Symbol *addUndefined(StringRef Name);
template <class ELFT>
Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther,
uint8_t Type, bool CanOmitFromDynSym, InputFile *File);
- Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type,
- uint64_t Value, uint64_t Size, uint8_t Binding,
- SectionBase *Section, InputFile *File);
+
+ Defined *addDefined(StringRef Name, uint8_t StOther, uint8_t Type,
+ uint64_t Value, uint64_t Size, uint8_t Binding,
+ SectionBase *Section, InputFile *File);
template <class ELFT>
void addShared(StringRef Name, SharedFile<ELFT> &F,
@@ -72,10 +67,8 @@ public:
uint8_t Binding, uint8_t StOther, uint8_t Type,
InputFile &File);
- std::pair<Symbol *, bool> insert(StringRef Name);
- std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type,
- uint8_t Visibility, bool CanOmitFromDynSym,
- InputFile *File);
+ std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Visibility,
+ bool CanOmitFromDynSym, InputFile *File);
template <class ELFT> void fetchLazy(Symbol *Sym);
@@ -88,6 +81,8 @@ public:
void handleDynamicList();
private:
+ std::pair<Symbol *, bool> insertName(StringRef Name);
+
std::vector<Symbol *> findByVersion(SymbolVersion Ver);
std::vector<Symbol *> findAllByVersion(SymbolVersion Ver);
@@ -113,7 +108,7 @@ private:
llvm::DenseSet<llvm::CachedHashStringRef> ComdatGroups;
// Set of .so files to not link the same shared object file more than once.
- llvm::DenseSet<StringRef> SoNames;
+ llvm::DenseMap<StringRef, InputFile *> SoNames;
// A map from demangled symbol names to their symbol objects.
// This mapping is 1:N because two symbols with different versions
@@ -121,15 +116,6 @@ private:
// directive in version scripts.
llvm::Optional<llvm::StringMap<std::vector<Symbol *>>> DemangledSyms;
- struct WrappedSymbol {
- Symbol *Sym;
- Symbol *Real;
- Symbol *Wrap;
- };
-
- // For -wrap.
- std::vector<WrappedSymbol> WrappedSymbols;
-
// For LTO.
std::unique_ptr<BitcodeCompiler> LTO;
};
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 4243cb1e80ef..a713ec539d82 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -38,6 +38,7 @@ Defined *ElfSym::GlobalOffsetTable;
Defined *ElfSym::MipsGp;
Defined *ElfSym::MipsGpDisp;
Defined *ElfSym::MipsLocalGp;
+Defined *ElfSym::RelaIpltStart;
Defined *ElfSym::RelaIpltEnd;
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
@@ -90,10 +91,15 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
uint64_t VA = IS->getVA(Offset);
if (D.isTls() && !Config->Relocatable) {
- if (!Out::TlsPhdr)
+ // Use the address of the TLS segment's first section rather than the
+ // segment's address, because segment addresses aren't initialized until
+ // after sections are finalized. (e.g. Measuring the size of .rela.dyn
+ // for Android relocation packing requires knowing TLS symbol addresses
+ // during section finalization.)
+ if (!Out::TlsPhdr || !Out::TlsPhdr->FirstSec)
fatal(toString(D.File) +
" has an STT_TLS symbol but doesn't have an SHF_TLS section");
- return VA - Out::TlsPhdr->p_vaddr;
+ return VA - Out::TlsPhdr->FirstSec->Addr;
}
return VA;
}
@@ -102,7 +108,10 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
return 0;
case Symbol::LazyArchiveKind:
case Symbol::LazyObjectKind:
- llvm_unreachable("lazy symbol reached writer");
+ assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
+ return 0;
+ case Symbol::PlaceholderKind:
+ llvm_unreachable("placeholder symbol reached writer");
}
llvm_unreachable("invalid symbol kind");
}
@@ -112,7 +121,7 @@ uint64_t Symbol::getVA(int64_t Addend) const {
return OutVA + Addend;
}
-uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); }
+uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); }
uint64_t Symbol::getGotOffset() const {
return GotIndex * Target->GotEntrySize;
@@ -120,8 +129,8 @@ uint64_t Symbol::getGotOffset() const {
uint64_t Symbol::getGotPltVA() const {
if (this->IsInIgot)
- return InX::IgotPlt->getVA() + getGotPltOffset();
- return InX::GotPlt->getVA() + getGotPltOffset();
+ return In.IgotPlt->getVA() + getGotPltOffset();
+ return In.GotPlt->getVA() + getGotPltOffset();
}
uint64_t Symbol::getGotPltOffset() const {
@@ -130,15 +139,20 @@ uint64_t Symbol::getGotPltOffset() const {
return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
}
+uint64_t Symbol::getPPC64LongBranchOffset() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
uint64_t Symbol::getPltVA() const {
- if (this->IsInIplt)
- return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
- return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex);
+ PltSection *Plt = IsInIplt ? In.Iplt : In.Plt;
+ return Plt->getVA() + Plt->HeaderSize + PltIndex * Target->PltEntrySize;
}
-uint64_t Symbol::getPltOffset() const {
- assert(!this->IsInIplt);
- return Target->getPltEntryOffset(PltIndex);
+uint64_t Symbol::getPPC64LongBranchTableVA() const {
+ assert(PPC64BranchltIndex != 0xffff);
+ return In.PPC64LongBranchTarget->getVA() +
+ PPC64BranchltIndex * Target->GotPltEntrySize;
}
uint64_t Symbol::getSize() const {
@@ -204,12 +218,21 @@ void Symbol::parseSymbolVersion() {
InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); }
+MemoryBufferRef LazyArchive::getMemberBuffer() {
+ Archive::Child C = CHECK(
+ Sym.getMember(), "could not get the member for symbol " + Sym.getName());
+
+ return CHECK(C.getMemoryBufferRef(),
+ "could not get the buffer for the member defining symbol " +
+ Sym.getName());
+}
+
uint8_t Symbol::computeBinding() const {
if (Config->Relocatable)
return Binding;
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (VersionId == VER_NDX_LOCAL && isDefined())
+ if (VersionId == VER_NDX_LOCAL && isDefined() && !IsPreemptible)
return STB_LOCAL;
if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE)
return STB_GLOBAL;
@@ -243,10 +266,19 @@ void elf::printTraceSymbol(Symbol *Sym) {
message(toString(Sym->File) + S + Sym->getName());
}
-void elf::warnUnorderableSymbol(const Symbol *Sym) {
+void elf::maybeWarnUnorderableSymbol(const Symbol *Sym) {
if (!Config->WarnSymbolOrdering)
return;
+ // If UnresolvedPolicy::Ignore is used, no "undefined symbol" error/warning
+ // is emitted. It makes sense to not warn on undefined symbols.
+ //
+ // Note, ld.bfd --symbol-ordering-file= does not warn on undefined symbols,
+ // but we don't have to be compatible here.
+ if (Sym->isUndefined() &&
+ Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+ return;
+
const InputFile *File = Sym->File;
auto *D = dyn_cast<Defined>(Sym);
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 8c9513b9368b..4d55405d8936 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -22,6 +22,14 @@
namespace lld {
namespace elf {
+class Symbol;
+class InputFile;
+} // namespace elf
+
+std::string toString(const elf::Symbol &);
+std::string toString(const elf::InputFile *);
+
+namespace elf {
class ArchiveFile;
class BitcodeFile;
@@ -50,6 +58,7 @@ struct StringRefZ {
class Symbol {
public:
enum Kind {
+ PlaceholderKind,
DefinedKind,
SharedKind,
UndefinedKind,
@@ -70,6 +79,7 @@ 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.
@@ -78,6 +88,9 @@ public:
// Version definition index.
uint16_t VersionId;
+ // An index into the .branch_lt section on PPC64.
+ uint16_t PPC64BranchltIndex = -1;
+
// 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.
@@ -89,7 +102,7 @@ public:
uint8_t Type; // symbol type
uint8_t StOther; // st_other field value
- const uint8_t SymbolKind;
+ uint8_t SymbolKind;
// Symbol visibility. This is the computed minimum visibility of all
// observed non-DSO symbols.
@@ -128,8 +141,12 @@ public:
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
}
- // True if this is an undefined weak symbol.
- bool isUndefWeak() const { return isWeak() && isUndefined(); }
+ // True if this is an undefined weak symbol. This only works once
+ // all input files have been added.
+ bool isUndefWeak() const {
+ // See comment on lazy symbols for details.
+ return isWeak() && (isUndefined() || isLazy());
+ }
StringRef getName() const {
if (NameSize == (uint32_t)-1)
@@ -137,10 +154,16 @@ public:
return {NameData, NameSize};
}
+ void setName(StringRef S) {
+ NameData = S.data();
+ NameSize = S.size();
+ }
+
void parseSymbolVersion();
bool isInGot() const { return GotIndex != -1U; }
bool isInPlt() const { return PltIndex != -1U; }
+ bool isInPPC64Branchlt() const { return PPC64BranchltIndex != 0xffff; }
uint64_t getVA(int64_t Addend = 0) const;
@@ -149,7 +172,8 @@ public:
uint64_t getGotPltOffset() const;
uint64_t getGotPltVA() const;
uint64_t getPltVA() const;
- uint64_t getPltOffset() const;
+ uint64_t getPPC64LongBranchTableVA() const;
+ uint64_t getPPC64LongBranchOffset() const;
uint64_t getSize() const;
OutputSection *getOutputSection() const;
@@ -159,7 +183,8 @@ protected:
: 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) {}
+ Used(!Config->GcSections), NeedsTocRestore(false),
+ ScriptDefined(false) {}
public:
// True the symbol should point to its PLT entry.
@@ -182,12 +207,8 @@ public:
// 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
- // Type field is normally set to this value for Lazy symbols unless we saw a
- // weak undefined symbol first, in which case we need to remember the original
- // symbol's type in order to check for TLS mismatches.
- enum { UnknownType = 255 };
+ // True if this symbol is defined by a linker script.
+ unsigned ScriptDefined : 1;
bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
bool isTls() const { return Type == llvm::ELF::STT_TLS; }
@@ -286,6 +307,7 @@ public:
static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; }
InputFile *fetch();
+ MemoryBufferRef getMemberBuffer();
private:
const llvm::object::Archive::Symbol Sym;
@@ -330,7 +352,8 @@ struct ElfSym {
static Defined *MipsGpDisp;
static Defined *MipsLocalGp;
- // __rela_iplt_end or __rel_iplt_end
+ // __rel{,a}_iplt_{start,end} symbols.
+ static Defined *RelaIpltStart;
static Defined *RelaIpltEnd;
};
@@ -349,6 +372,8 @@ void printTraceSymbol(Symbol *Sym);
template <typename T, typename... ArgT>
void replaceSymbol(Symbol *S, ArgT &&... Arg) {
+ using llvm::ELF::STT_TLS;
+
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
@@ -367,6 +392,19 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
S->ExportDynamic = Sym.ExportDynamic;
S->CanInline = Sym.CanInline;
S->Traced = Sym.Traced;
+ S->ScriptDefined = Sym.ScriptDefined;
+
+ // Symbols representing thread-local variables must be referenced by
+ // TLS-aware relocations, and non-TLS symbols must be reference by
+ // non-TLS relocations, so there's a clear distinction between TLS
+ // and non-TLS symbols. It is an error if the same symbol is defined
+ // as a TLS symbol in one file and as a non-TLS symbol in other file.
+ bool TlsMismatch = (Sym.Type == STT_TLS && S->Type != STT_TLS) ||
+ (Sym.Type != STT_TLS && S->Type == STT_TLS);
+
+ if (Sym.SymbolKind != Symbol::PlaceholderKind && TlsMismatch && !Sym.isLazy())
+ error("TLS attribute mismatch: " + toString(Sym) + "\n>>> defined in " +
+ toString(Sym.File) + "\n>>> defined in " + toString(S->File));
// Print out a log message if --trace-symbol was specified.
// This is for debugging.
@@ -374,10 +412,8 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) {
printTraceSymbol(S);
}
-void warnUnorderableSymbol(const Symbol *Sym);
+void maybeWarnUnorderableSymbol(const Symbol *Sym);
} // namespace elf
-
-std::string toString(const elf::Symbol &B);
} // namespace lld
#endif
diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp
index ae02434572c2..f459c1b6b479 100644
--- a/ELF/SyntheticSections.cpp
+++ b/ELF/SyntheticSections.cpp
@@ -30,10 +30,11 @@
#include "lld/Common/Threads.h"
#include "lld/Common/Version.h"
#include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
-#include "llvm/Object/Decompressor.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MD5.h"
@@ -104,7 +105,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Create = true;
std::string Filename = toString(Sec->File);
- const size_t Size = Sec->Data.size();
+ const size_t Size = Sec->data().size();
// Older version of BFD (such as the default FreeBSD linker) concatenate
// .MIPS.abiflags instead of merging. To allow for this case (or potential
// zero padding) we ignore everything after the first Elf_Mips_ABIFlags
@@ -113,7 +114,7 @@ MipsAbiFlagsSection<ELFT> *MipsAbiFlagsSection<ELFT>::create() {
Twine(Size) + " instead of " + Twine(sizeof(Elf_Mips_ABIFlags)));
return nullptr;
}
- auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->Data.data());
+ auto *S = reinterpret_cast<const Elf_Mips_ABIFlags *>(Sec->data().data());
if (S->version != 0) {
error(Filename + ": unexpected .MIPS.abiflags version " +
Twine(S->version));
@@ -153,7 +154,7 @@ template <class ELFT> void MipsOptionsSection<ELFT>::writeTo(uint8_t *Buf) {
Options->size = getSize();
if (!Config->Relocatable)
- Reginfo.ri_gp_value = InX::MipsGot->getGp();
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf + sizeof(Elf_Mips_Options), &Reginfo, sizeof(Reginfo));
}
@@ -176,7 +177,7 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() {
Sec->Live = false;
std::string Filename = toString(Sec->File);
- ArrayRef<uint8_t> D = Sec->Data;
+ ArrayRef<uint8_t> D = Sec->data();
while (!D.empty()) {
if (D.size() < sizeof(Elf_Mips_Options)) {
@@ -210,7 +211,7 @@ MipsReginfoSection<ELFT>::MipsReginfoSection(Elf_Mips_RegInfo Reginfo)
template <class ELFT> void MipsReginfoSection<ELFT>::writeTo(uint8_t *Buf) {
if (!Config->Relocatable)
- Reginfo.ri_gp_value = InX::MipsGot->getGp();
+ Reginfo.ri_gp_value = In.MipsGot->getGp();
memcpy(Buf, &Reginfo, sizeof(Reginfo));
}
@@ -232,12 +233,12 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() {
for (InputSectionBase *Sec : Sections) {
Sec->Live = false;
- if (Sec->Data.size() != sizeof(Elf_Mips_RegInfo)) {
+ if (Sec->data().size() != sizeof(Elf_Mips_RegInfo)) {
error(toString(Sec->File) + ": invalid size of .reginfo section");
return nullptr;
}
- auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data());
+ 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;
};
@@ -260,8 +261,8 @@ 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)
- InX::SymTab->addSymbol(S);
+ if (In.SymTab)
+ In.SymTab->addSymbol(S);
return S;
}
@@ -502,7 +503,7 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const {
uint8_t *Buf = getParent()->Loc + OutSecOff;
std::vector<FdeData> Ret;
- uint64_t VA = InX::EhFrameHdr->getVA();
+ uint64_t VA = In.EhFrameHdr->getVA();
for (CieRecord *Rec : CieRecords) {
uint8_t Enc = getFdeEncoding(Rec->Cie);
for (EhSectionPiece *Fde : Rec->Fdes) {
@@ -937,7 +938,7 @@ template <class ELFT> void MipsGotSection::build() {
Symbol *S = P.first;
uint64_t Offset = P.second * Config->Wordsize;
if (S->IsPreemptible)
- InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
+ In.RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S);
}
for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) {
Symbol *S = P.first;
@@ -945,7 +946,7 @@ template <class ELFT> void MipsGotSection::build() {
if (S == nullptr) {
if (!Config->Pic)
continue;
- InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S);
+ In.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
@@ -953,13 +954,13 @@ template <class ELFT> void MipsGotSection::build() {
// 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);
+ In.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);
+ In.RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S);
}
}
@@ -971,7 +972,7 @@ template <class ELFT> void MipsGotSection::build() {
// 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);
+ In.RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first);
}
if (!Config->Pic)
continue;
@@ -981,14 +982,14 @@ template <class ELFT> void MipsGotSection::build() {
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)});
+ In.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});
+ In.RelaDyn->addReloc({Target->RelativeRel, this, Offset, true,
+ P.first.first, P.first.second});
}
}
}
@@ -1200,21 +1201,21 @@ DynamicSection<ELFT>::DynamicSection()
// Add strings to .dynstr early so that .dynstr's size will be
// fixed early.
for (StringRef S : Config->FilterList)
- addInt(DT_FILTER, InX::DynStrTab->addString(S));
+ addInt(DT_FILTER, In.DynStrTab->addString(S));
for (StringRef S : Config->AuxiliaryList)
- addInt(DT_AUXILIARY, InX::DynStrTab->addString(S));
+ addInt(DT_AUXILIARY, In.DynStrTab->addString(S));
if (!Config->Rpath.empty())
addInt(Config->EnableNewDtags ? DT_RUNPATH : DT_RPATH,
- InX::DynStrTab->addString(Config->Rpath));
+ In.DynStrTab->addString(Config->Rpath));
for (InputFile *File : SharedFiles) {
SharedFile<ELFT> *F = cast<SharedFile<ELFT>>(File);
if (F->IsNeeded)
- addInt(DT_NEEDED, InX::DynStrTab->addString(F->SoName));
+ addInt(DT_NEEDED, In.DynStrTab->addString(F->SoName));
}
if (!Config->SoName.empty())
- addInt(DT_SONAME, InX::DynStrTab->addString(Config->SoName));
+ addInt(DT_SONAME, In.DynStrTab->addString(Config->SoName));
}
template <class ELFT>
@@ -1254,18 +1255,33 @@ void DynamicSection<ELFT>::addSym(int32_t Tag, Symbol *Sym) {
Entries.push_back({Tag, [=] { return Sym->getVA(); }});
}
+// A Linker script may assign the RELA relocation sections to the same
+// output section. When this occurs we cannot just use the OutputSection
+// Size. Moreover the [DT_JMPREL, DT_JMPREL + DT_PLTRELSZ) is permitted to
+// overlap with the [DT_RELA, DT_RELA + DT_RELASZ).
+static uint64_t addPltRelSz() {
+ size_t Size = In.RelaPlt->getSize();
+ if (In.RelaIplt->getParent() == In.RelaPlt->getParent() &&
+ In.RelaIplt->Name == In.RelaPlt->Name)
+ Size += In.RelaIplt->getSize();
+ return Size;
+}
+
// Add remaining entries to complete .dynamic contents.
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
- if (this->Size)
- return; // Already finalized.
-
// Set DT_FLAGS and DT_FLAGS_1.
uint32_t DtFlags = 0;
uint32_t DtFlags1 = 0;
if (Config->Bsymbolic)
DtFlags |= DF_SYMBOLIC;
+ if (Config->ZGlobal)
+ DtFlags1 |= DF_1_GLOBAL;
if (Config->ZInitfirst)
DtFlags1 |= DF_1_INITFIRST;
+ if (Config->ZInterpose)
+ DtFlags1 |= DF_1_INTERPOSE;
+ if (Config->ZNodefaultlib)
+ DtFlags1 |= DF_1_NODEFLIB;
if (Config->ZNodelete)
DtFlags1 |= DF_1_NODELETE;
if (Config->ZNodlopen)
@@ -1297,10 +1313,12 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)
addInt(DT_DEBUG, 0);
- this->Link = InX::DynStrTab->getParent()->SectionIndex;
- if (!InX::RelaDyn->empty()) {
- addInSec(InX::RelaDyn->DynamicTag, InX::RelaDyn);
- addSize(InX::RelaDyn->SizeDynamicTag, InX::RelaDyn->getParent());
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ this->Link = Sec->SectionIndex;
+
+ if (!In.RelaDyn->empty()) {
+ addInSec(In.RelaDyn->DynamicTag, In.RelaDyn);
+ addSize(In.RelaDyn->SizeDynamicTag, In.RelaDyn->getParent());
bool IsRela = Config->IsRela;
addInt(IsRela ? DT_RELAENT : DT_RELENT,
@@ -1310,16 +1328,16 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// The problem is in the tight relation between dynamic
// relocations and GOT. So do not emit this tag on MIPS.
if (Config->EMachine != EM_MIPS) {
- size_t NumRelativeRels = InX::RelaDyn->getRelativeRelocCount();
+ size_t NumRelativeRels = In.RelaDyn->getRelativeRelocCount();
if (Config->ZCombreloc && NumRelativeRels)
addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels);
}
}
- if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) {
+ if (In.RelrDyn && !In.RelrDyn->Relocs.empty()) {
addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
- InX::RelrDyn);
+ In.RelrDyn);
addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
- InX::RelrDyn->getParent());
+ In.RelrDyn->getParent());
addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
sizeof(Elf_Relr));
}
@@ -1329,33 +1347,33 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
// 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());
+ if (In.RelaPlt->getParent()->Live) {
+ addInSec(DT_JMPREL, In.RelaPlt);
+ Entries.push_back({DT_PLTRELSZ, addPltRelSz});
switch (Config->EMachine) {
case EM_MIPS:
- addInSec(DT_MIPS_PLTGOT, InX::GotPlt);
+ addInSec(DT_MIPS_PLTGOT, In.GotPlt);
break;
case EM_SPARCV9:
- addInSec(DT_PLTGOT, InX::Plt);
+ addInSec(DT_PLTGOT, In.Plt);
break;
default:
- addInSec(DT_PLTGOT, InX::GotPlt);
+ addInSec(DT_PLTGOT, In.GotPlt);
break;
}
addInt(DT_PLTREL, Config->IsRela ? DT_RELA : DT_REL);
}
- addInSec(DT_SYMTAB, InX::DynSymTab);
+ addInSec(DT_SYMTAB, In.DynSymTab);
addInt(DT_SYMENT, sizeof(Elf_Sym));
- addInSec(DT_STRTAB, InX::DynStrTab);
- addInt(DT_STRSZ, InX::DynStrTab->getSize());
+ addInSec(DT_STRTAB, In.DynStrTab);
+ addInt(DT_STRSZ, In.DynStrTab->getSize());
if (!Config->ZText)
addInt(DT_TEXTREL, 0);
- if (InX::GnuHashTab)
- addInSec(DT_GNU_HASH, InX::GnuHashTab);
- if (InX::HashTab)
- addInSec(DT_HASH, InX::HashTab);
+ if (In.GnuHashTab)
+ addInSec(DT_GNU_HASH, In.GnuHashTab);
+ if (In.HashTab)
+ addInSec(DT_HASH, In.HashTab);
if (Out::PreinitArray) {
addOutSec(DT_PREINIT_ARRAY, Out::PreinitArray);
@@ -1377,47 +1395,47 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
if (B->isDefined())
addSym(DT_FINI, B);
- bool HasVerNeed = In<ELFT>::VerNeed->getNeedNum() != 0;
- if (HasVerNeed || In<ELFT>::VerDef)
- addInSec(DT_VERSYM, In<ELFT>::VerSym);
- if (In<ELFT>::VerDef) {
- addInSec(DT_VERDEF, In<ELFT>::VerDef);
+ bool HasVerNeed = InX<ELFT>::VerNeed->getNeedNum() != 0;
+ if (HasVerNeed || In.VerDef)
+ addInSec(DT_VERSYM, InX<ELFT>::VerSym);
+ if (In.VerDef) {
+ addInSec(DT_VERDEF, In.VerDef);
addInt(DT_VERDEFNUM, getVerDefNum());
}
if (HasVerNeed) {
- addInSec(DT_VERNEED, In<ELFT>::VerNeed);
- addInt(DT_VERNEEDNUM, In<ELFT>::VerNeed->getNeedNum());
+ addInSec(DT_VERNEED, InX<ELFT>::VerNeed);
+ addInt(DT_VERNEEDNUM, InX<ELFT>::VerNeed->getNeedNum());
}
if (Config->EMachine == EM_MIPS) {
addInt(DT_MIPS_RLD_VERSION, 1);
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
addInt(DT_MIPS_BASE_ADDRESS, Target->getImageBase());
- addInt(DT_MIPS_SYMTABNO, InX::DynSymTab->getNumSymbols());
+ addInt(DT_MIPS_SYMTABNO, In.DynSymTab->getNumSymbols());
- add(DT_MIPS_LOCAL_GOTNO, [] { return InX::MipsGot->getLocalEntriesNum(); });
+ add(DT_MIPS_LOCAL_GOTNO, [] { return In.MipsGot->getLocalEntriesNum(); });
- if (const Symbol *B = InX::MipsGot->getFirstGlobalEntry())
+ if (const Symbol *B = In.MipsGot->getFirstGlobalEntry())
addInt(DT_MIPS_GOTSYM, B->DynsymIndex);
else
- addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols());
- addInSec(DT_PLTGOT, InX::MipsGot);
- if (InX::MipsRldMap) {
+ addInt(DT_MIPS_GOTSYM, In.DynSymTab->getNumSymbols());
+ addInSec(DT_PLTGOT, In.MipsGot);
+ if (In.MipsRldMap) {
if (!Config->Pie)
- addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap);
+ addInSec(DT_MIPS_RLD_MAP, In.MipsRldMap);
// Store the offset to the .rld_map section
// relative to the address of the tag.
- addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap);
+ addInSecRelative(DT_MIPS_RLD_MAP_REL, In.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()) {
+ if (Config->EMachine == EM_PPC64 && !In.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;
+ return In.Plt->getVA(0) + Offset;
}});
}
@@ -1486,13 +1504,17 @@ void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) {
}
void RelocationBaseSection::finalizeContents() {
- // If all relocations are R_*_RELATIVE they don't refer to any
- // dynamic symbol and we don't need a dynamic symbol table. If that
- // is the case, just use 0 as the link.
- Link = InX::DynSymTab ? InX::DynSymTab->getParent()->SectionIndex : 0;
+ // When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
+ // relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
+ // case.
+ InputSection *SymTab = Config->Relocatable ? In.SymTab : In.DynSymTab;
+ if (SymTab && SymTab->getParent())
+ getParent()->Link = SymTab->getParent()->SectionIndex;
+ else
+ getParent()->Link = 0;
- // Set required output section properties.
- getParent()->Link = Link;
+ if (In.RelaIplt == this || In.RelaPlt == this)
+ getParent()->Info = In.GotPlt->getParent()->SectionIndex;
}
RelrBaseSection::RelrBaseSection()
@@ -1621,10 +1643,9 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
NonRelatives.push_back(R);
}
- llvm::sort(Relatives.begin(), Relatives.end(),
- [](const Elf_Rel &A, const Elf_Rel &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(Relatives, [](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
@@ -1702,10 +1723,9 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
// Finally the non-relative relocations.
- llvm::sort(NonRelatives.begin(), NonRelatives.end(),
- [](const Elf_Rela &A, const Elf_Rela &B) {
- return A.r_offset < B.r_offset;
- });
+ llvm::sort(NonRelatives, [](const Elf_Rela &A, const Elf_Rela &B) {
+ return A.r_offset < B.r_offset;
+ });
if (!NonRelatives.empty()) {
Add(NonRelatives.size());
Add(HasAddendIfRela);
@@ -1720,6 +1740,11 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() {
}
}
+ // Don't allow the section to shrink; otherwise the size of the section can
+ // oscillate infinitely.
+ if (RelocData.size() < OldSize)
+ RelocData.append(OldSize - RelocData.size(), 0);
+
// Returns whether the section size changed. We need to keep recomputing both
// section layout and the contents of this section until the size converges
// because changing this section's size can affect section layout, which in
@@ -1843,10 +1868,13 @@ static bool sortMipsSymbols(const SymbolTableEntry &L,
}
void SymbolTableBaseSection::finalizeContents() {
- getParent()->Link = StrTabSec.getParent()->SectionIndex;
+ if (OutputSection *Sec = StrTabSec.getParent())
+ getParent()->Link = Sec->SectionIndex;
- if (this->Type != SHT_DYNSYM)
+ if (this->Type != SHT_DYNSYM) {
+ sortSymTabSymbols();
return;
+ }
// If it is a .dynsym, there should be no local symbols, but we need
// to do a few things for the dynamic linker.
@@ -1855,9 +1883,9 @@ void SymbolTableBaseSection::finalizeContents() {
// Because the first symbol entry is a null entry, 1 is the first.
getParent()->Info = 1;
- if (InX::GnuHashTab) {
+ if (In.GnuHashTab) {
// NB: It also sorts Symbols to meet the GNU hash table requirements.
- InX::GnuHashTab->addSymbols(Symbols);
+ In.GnuHashTab->addSymbols(Symbols);
} else if (Config->EMachine == EM_MIPS) {
std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols);
}
@@ -1874,9 +1902,7 @@ void SymbolTableBaseSection::finalizeContents() {
// 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() {
- assert(this->Type == SHT_SYMTAB);
-
+void SymbolTableBaseSection::sortSymTabSymbols() {
// Move all local symbols before global symbols.
auto E = std::stable_partition(
Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) {
@@ -1948,7 +1974,8 @@ static uint32_t getSymSectionIndex(Symbol *Sym) {
if (!isa<Defined>(Sym) || Sym->NeedsPltAddr)
return SHN_UNDEF;
if (const OutputSection *OS = Sym->getOutputSection())
- return OS->SectionIndex >= SHN_LORESERVE ? SHN_XINDEX : OS->SectionIndex;
+ return OS->SectionIndex >= SHN_LORESERVE ? (uint32_t)SHN_XINDEX
+ : OS->SectionIndex;
return SHN_ABS;
}
@@ -2038,7 +2065,7 @@ void SymtabShndxSection::writeTo(uint8_t *Buf) {
// with an entry in .symtab. If the corresponding entry contains SHN_XINDEX,
// we need to write actual index, otherwise, we must write SHN_UNDEF(0).
Buf += 4; // Ignore .symtab[0] entry.
- for (const SymbolTableEntry &Entry : InX::SymTab->getSymbols()) {
+ for (const SymbolTableEntry &Entry : In.SymTab->getSymbols()) {
if (getSymSectionIndex(Entry.Sym) == SHN_XINDEX)
write32(Buf, Entry.Sym->getOutputSection()->SectionIndex);
Buf += 4;
@@ -2059,11 +2086,11 @@ bool SymtabShndxSection::empty() const {
}
void SymtabShndxSection::finalizeContents() {
- getParent()->Link = InX::SymTab->getParent()->SectionIndex;
+ getParent()->Link = In.SymTab->getParent()->SectionIndex;
}
size_t SymtabShndxSection::getSize() const {
- return InX::SymTab->getNumSymbols() * 4;
+ return In.SymTab->getNumSymbols() * 4;
}
// .hash and .gnu.hash sections contain on-disk hash tables that map
@@ -2102,7 +2129,8 @@ GnuHashTableSection::GnuHashTableSection()
}
void GnuHashTableSection::finalizeContents() {
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
// Computes bloom filter size in word size. We want to allocate 12
// bits for each symbol. It must be a power of two.
@@ -2127,7 +2155,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
// Write a header.
write32(Buf, NBuckets);
- write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size());
+ write32(Buf + 4, In.DynSymTab->getNumSymbols() - Symbols.size());
write32(Buf + 8, MaskWords);
write32(Buf + 12, Shift2);
Buf += 16;
@@ -2148,6 +2176,8 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) {
void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) {
unsigned C = Config->Is64 ? 64 : 32;
for (const Entry &Sym : Symbols) {
+ // When C = 64, we choose a word with bits [6:...] and set 1 to two bits in
+ // the word using bits [0:5] and [26:31].
size_t I = (Sym.Hash / C) & (MaskWords - 1);
uint64_t Val = readUint(Buf + I * Config->Wordsize);
Val |= uint64_t(1) << (Sym.Hash % C);
@@ -2232,13 +2262,14 @@ HashTableSection::HashTableSection()
}
void HashTableSection::finalizeContents() {
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynSymTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += InX::DynSymTab->getNumSymbols(); // The chain entries.
+ NumEntries += In.DynSymTab->getNumSymbols(); // The chain entries.
// Create as many buckets as there are symbols.
- NumEntries += InX::DynSymTab->getNumSymbols();
+ NumEntries += In.DynSymTab->getNumSymbols();
this->Size = NumEntries * 4;
}
@@ -2246,7 +2277,7 @@ void HashTableSection::writeTo(uint8_t *Buf) {
// See comment in GnuHashTableSection::writeTo.
memset(Buf, 0, Size);
- unsigned NumSymbols = InX::DynSymTab->getNumSymbols();
+ unsigned NumSymbols = In.DynSymTab->getNumSymbols();
uint32_t *P = reinterpret_cast<uint32_t *>(Buf);
write32(P++, NumSymbols); // nbucket
@@ -2255,7 +2286,7 @@ void HashTableSection::writeTo(uint8_t *Buf) {
uint32_t *Buckets = P;
uint32_t *Chains = P + NumSymbols;
- for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
Symbol *Sym = S.Sym;
StringRef Name = Sym->getName();
unsigned I = Sym->DynsymIndex;
@@ -2270,7 +2301,8 @@ void HashTableSection::writeTo(uint8_t *Buf) {
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) {
+ HeaderSize(!IsIplt || Config->ZRetpolineplt ? Target->PltHeaderSize : 0),
+ 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)
@@ -2278,9 +2310,9 @@ PltSection::PltSection(bool IsIplt)
}
void PltSection::writeTo(uint8_t *Buf) {
- // At beginning of PLT but not the IPLT, we have code to call the dynamic
+ // At beginning of PLT or retpoline IPLT, we have code to call the dynamic
// linker to resolve dynsyms at runtime. Write such code.
- if (!IsIplt)
+ if (HeaderSize > 0)
Target->writePltHeader(Buf);
size_t Off = HeaderSize;
// The IPlt is immediately after the Plt, account for this in RelOff
@@ -2298,9 +2330,9 @@ void PltSection::writeTo(uint8_t *Buf) {
template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
Sym.PltIndex = Entries.size();
- RelocationBaseSection *PltRelocSection = InX::RelaPlt;
+ RelocationBaseSection *PltRelocSection = In.RelaPlt;
if (IsIplt) {
- PltRelocSection = InX::RelaIplt;
+ PltRelocSection = In.RelaIplt;
Sym.IsInIplt = true;
}
unsigned RelOff =
@@ -2326,14 +2358,14 @@ void PltSection::addSymbols() {
}
unsigned PltSection::getPltRelocOff() const {
- return IsIplt ? InX::Plt->getSize() : 0;
+ return IsIplt ? In.Plt->getSize() : 0;
}
// The string hash function for .gdb_index.
static uint32_t computeGdbHash(StringRef S) {
uint32_t H = 0;
for (uint8_t C : S)
- H = H * 67 + tolower(C) - 113;
+ H = H * 67 + toLower(C) - 113;
return H;
}
@@ -2371,7 +2403,7 @@ static std::vector<InputSection *> getDebugInfoSections() {
static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) {
std::vector<GdbIndexSection::CuEntry> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units())
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units())
Ret.push_back({Cu->getOffset(), Cu->getLength() + 4});
return Ret;
}
@@ -2381,12 +2413,15 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
std::vector<GdbIndexSection::AddressEntry> Ret;
uint32_t CuIdx = 0;
- for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) {
- DWARFAddressRangesVector Ranges;
- Cu->collectAddressRanges(Ranges);
+ for (std::unique_ptr<DWARFUnit> &Cu : Dwarf.compile_units()) {
+ Expected<DWARFAddressRangesVector> Ranges = Cu->collectAddressRanges();
+ if (!Ranges) {
+ error(toString(Sec) + ": " + toString(Ranges.takeError()));
+ return {};
+ }
ArrayRef<InputSectionBase *> Sections = Sec->File->getSections();
- for (DWARFAddressRange &R : Ranges) {
+ for (DWARFAddressRange &R : *Ranges) {
InputSectionBase *S = Sections[R.SectionIndex];
if (!S || S == &InputSection::Discarded || !S->Live)
continue;
@@ -2399,21 +2434,35 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) {
}
++CuIdx;
}
+
return Ret;
}
-static std::vector<GdbIndexSection::NameTypeEntry>
-readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
- StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection();
- StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection();
-
- std::vector<GdbIndexSection::NameTypeEntry> Ret;
- for (StringRef Sec : {Sec1, Sec2}) {
- DWARFDebugPubTable Table(Sec, Config->IsLE, true);
- for (const DWARFDebugPubTable::Set &Set : Table.getData())
+template <class ELFT>
+static std::vector<GdbIndexSection::NameAttrEntry>
+readPubNamesAndTypes(const LLDDwarfObj<ELFT> &Obj,
+ const std::vector<GdbIndexSection::CuEntry> &CUs) {
+ const DWARFSection &PubNames = Obj.getGnuPubNamesSection();
+ const DWARFSection &PubTypes = Obj.getGnuPubTypesSection();
+
+ std::vector<GdbIndexSection::NameAttrEntry> Ret;
+ for (const DWARFSection *Pub : {&PubNames, &PubTypes}) {
+ DWARFDebugPubTable Table(Obj, *Pub, Config->IsLE, true);
+ for (const DWARFDebugPubTable::Set &Set : Table.getData()) {
+ // The value written into the constant pool is Kind << 24 | CuIndex. As we
+ // don't know how many compilation units precede this object to compute
+ // CuIndex, we compute (Kind << 24 | CuIndexInThisObject) instead, and add
+ // the number of preceding compilation units later.
+ uint32_t I =
+ lower_bound(CUs, Set.Offset,
+ [](GdbIndexSection::CuEntry CU, uint32_t Offset) {
+ return CU.CuOffset < Offset;
+ }) -
+ CUs.begin();
for (const DWARFDebugPubTable::Entry &Ent : Set.Entries)
Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)},
- (Ent.Descriptor.toBits() << 24) | Idx});
+ (Ent.Descriptor.toBits() << 24) | I});
+ }
}
return Ret;
}
@@ -2421,9 +2470,18 @@ readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) {
// 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) {
+createSymbols(ArrayRef<std::vector<GdbIndexSection::NameAttrEntry>> NameAttrs,
+ const std::vector<GdbIndexSection::GdbChunk> &Chunks) {
typedef GdbIndexSection::GdbSymbol GdbSymbol;
- typedef GdbIndexSection::NameTypeEntry NameTypeEntry;
+ typedef GdbIndexSection::NameAttrEntry NameAttrEntry;
+
+ // For each chunk, compute the number of compilation units preceding it.
+ uint32_t CuIdx = 0;
+ std::vector<uint32_t> CuIdxs(Chunks.size());
+ for (uint32_t I = 0, E = Chunks.size(); I != E; ++I) {
+ CuIdxs[I] = CuIdx;
+ CuIdx += Chunks[I].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
@@ -2441,21 +2499,24 @@ createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) {
// 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) {
+ uint32_t I = 0;
+ for (ArrayRef<NameAttrEntry> Entries : NameAttrs) {
+ for (const NameAttrEntry &Ent : Entries) {
size_t ShardId = Ent.Name.hash() >> Shift;
if ((ShardId & (Concurrency - 1)) != ThreadId)
continue;
+ uint32_t V = Ent.CuIndexAndAttrs + CuIdxs[I];
size_t &Idx = Map[ShardId][Ent.Name];
if (Idx) {
- Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type);
+ Symbols[ShardId][Idx - 1].CuVector.push_back(V);
continue;
}
Idx = Symbols[ShardId].size() + 1;
- Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0});
+ Symbols[ShardId].push_back({Ent.Name, {V}, 0, 0});
}
+ ++I;
}
});
@@ -2498,7 +2559,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
S->Live = false;
std::vector<GdbChunk> Chunks(Sections.size());
- std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size());
+ std::vector<std::vector<NameAttrEntry>> NameAttrs(Sections.size());
parallelForEachN(0, Sections.size(), [&](size_t I) {
ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>();
@@ -2507,12 +2568,14 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
Chunks[I].Sec = Sections[I];
Chunks[I].CompilationUnits = readCuList(Dwarf);
Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]);
- NameTypes[I] = readPubNamesAndTypes(Dwarf, I);
+ NameAttrs[I] = readPubNamesAndTypes<ELFT>(
+ static_cast<const LLDDwarfObj<ELFT> &>(Dwarf.getDWARFObj()),
+ Chunks[I].CompilationUnits);
});
auto *Ret = make<GdbIndexSection>();
Ret->Chunks = std::move(Chunks);
- Ret->Symbols = createSymbols(NameTypes);
+ Ret->Symbols = createSymbols(NameAttrs, Ret->Chunks);
Ret->initOutputSize();
return Ret;
}
@@ -2570,8 +2633,9 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
// Write the string pool.
Hdr->ConstantPoolOff = Buf - Start;
- for (GdbSymbol &Sym : Symbols)
+ parallelForEach(Symbols, [&](GdbSymbol &Sym) {
memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size());
+ });
// Write the CU vectors.
for (GdbSymbol &Sym : Symbols) {
@@ -2584,7 +2648,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {
}
}
-bool GdbIndexSection::empty() const { return !Out::DebugInfo; }
+bool GdbIndexSection::empty() const { return Chunks.empty(); }
EhFrameHeader::EhFrameHeader()
: SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {}
@@ -2596,13 +2660,13 @@ EhFrameHeader::EhFrameHeader()
void EhFrameHeader::writeTo(uint8_t *Buf) {
typedef EhFrameSection::FdeData FdeData;
- std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
+ std::vector<FdeData> Fdes = In.EhFrame->getFdeData();
Buf[0] = 1;
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
Buf[2] = DW_EH_PE_udata4;
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
- write32(Buf + 4, InX::EhFrame->getParent()->Addr - this->getVA() - 4);
+ write32(Buf + 4, In.EhFrame->getParent()->Addr - this->getVA() - 4);
write32(Buf + 8, Fdes.size());
Buf += 12;
@@ -2615,13 +2679,12 @@ void EhFrameHeader::writeTo(uint8_t *Buf) {
size_t EhFrameHeader::getSize() const {
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
- return 12 + InX::EhFrame->NumFdes * 8;
+ return 12 + In.EhFrame->NumFdes * 8;
}
-bool EhFrameHeader::empty() const { return InX::EhFrame->empty(); }
+bool EhFrameHeader::empty() const { return In.EhFrame->empty(); }
-template <class ELFT>
-VersionDefinitionSection<ELFT>::VersionDefinitionSection()
+VersionDefinitionSection::VersionDefinitionSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_verdef, sizeof(uint32_t),
".gnu.version_d") {}
@@ -2631,12 +2694,13 @@ static StringRef getFileDefName() {
return Config->OutputFile;
}
-template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
- FileDefNameOff = InX::DynStrTab->addString(getFileDefName());
+void VersionDefinitionSection::finalizeContents() {
+ FileDefNameOff = In.DynStrTab->addString(getFileDefName());
for (VersionDefinition &V : Config->VersionDefinitions)
- V.NameOff = InX::DynStrTab->addString(V.Name);
+ V.NameOff = In.DynStrTab->addString(V.Name);
- getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
// sh_info should be set to the number of definitions. This fact is missed in
// documentation, but confirmed by binutils community:
@@ -2644,68 +2708,68 @@ template <class ELFT> void VersionDefinitionSection<ELFT>::finalizeContents() {
getParent()->Info = getVerDefNum();
}
-template <class ELFT>
-void VersionDefinitionSection<ELFT>::writeOne(uint8_t *Buf, uint32_t Index,
- StringRef Name, size_t NameOff) {
- auto *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
- Verdef->vd_version = 1;
- Verdef->vd_cnt = 1;
- Verdef->vd_aux = sizeof(Elf_Verdef);
- Verdef->vd_next = sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
- Verdef->vd_flags = (Index == 1 ? VER_FLG_BASE : 0);
- Verdef->vd_ndx = Index;
- Verdef->vd_hash = hashSysV(Name);
-
- auto *Verdaux = reinterpret_cast<Elf_Verdaux *>(Buf + sizeof(Elf_Verdef));
- Verdaux->vda_name = NameOff;
- Verdaux->vda_next = 0;
+void VersionDefinitionSection::writeOne(uint8_t *Buf, uint32_t Index,
+ StringRef Name, size_t NameOff) {
+ uint16_t Flags = Index == 1 ? VER_FLG_BASE : 0;
+
+ // Write a verdef.
+ write16(Buf, 1); // vd_version
+ write16(Buf + 2, Flags); // vd_flags
+ write16(Buf + 4, Index); // vd_ndx
+ write16(Buf + 6, 1); // vd_cnt
+ write32(Buf + 8, hashSysV(Name)); // vd_hash
+ write32(Buf + 12, 20); // vd_aux
+ write32(Buf + 16, 28); // vd_next
+
+ // Write a veraux.
+ write32(Buf + 20, NameOff); // vda_name
+ write32(Buf + 24, 0); // vda_next
}
-template <class ELFT>
-void VersionDefinitionSection<ELFT>::writeTo(uint8_t *Buf) {
+void VersionDefinitionSection::writeTo(uint8_t *Buf) {
writeOne(Buf, 1, getFileDefName(), FileDefNameOff);
for (VersionDefinition &V : Config->VersionDefinitions) {
- Buf += sizeof(Elf_Verdef) + sizeof(Elf_Verdaux);
+ Buf += EntrySize;
writeOne(Buf, V.Id, V.Name, V.NameOff);
}
// Need to terminate the last version definition.
- Elf_Verdef *Verdef = reinterpret_cast<Elf_Verdef *>(Buf);
- Verdef->vd_next = 0;
+ write32(Buf + 16, 0); // vd_next
}
-template <class ELFT> size_t VersionDefinitionSection<ELFT>::getSize() const {
- return (sizeof(Elf_Verdef) + sizeof(Elf_Verdaux)) * getVerDefNum();
+size_t VersionDefinitionSection::getSize() const {
+ return EntrySize * getVerDefNum();
}
+// .gnu.version is a table where each entry is 2 byte long.
template <class ELFT>
VersionTableSection<ELFT>::VersionTableSection()
: SyntheticSection(SHF_ALLOC, SHT_GNU_versym, sizeof(uint16_t),
".gnu.version") {
- this->Entsize = sizeof(Elf_Versym);
+ this->Entsize = 2;
}
template <class ELFT> void VersionTableSection<ELFT>::finalizeContents() {
// At the moment of june 2016 GNU docs does not mention that sh_link field
// should be set, but Sun docs do. Also readelf relies on this field.
- getParent()->Link = InX::DynSymTab->getParent()->SectionIndex;
+ getParent()->Link = In.DynSymTab->getParent()->SectionIndex;
}
template <class ELFT> size_t VersionTableSection<ELFT>::getSize() const {
- return sizeof(Elf_Versym) * (InX::DynSymTab->getSymbols().size() + 1);
+ return (In.DynSymTab->getSymbols().size() + 1) * 2;
}
template <class ELFT> void VersionTableSection<ELFT>::writeTo(uint8_t *Buf) {
- auto *OutVersym = reinterpret_cast<Elf_Versym *>(Buf) + 1;
- for (const SymbolTableEntry &S : InX::DynSymTab->getSymbols()) {
- OutVersym->vs_index = S.Sym->VersionId;
- ++OutVersym;
+ Buf += 2;
+ for (const SymbolTableEntry &S : In.DynSymTab->getSymbols()) {
+ write16(Buf, S.Sym->VersionId);
+ Buf += 2;
}
}
template <class ELFT> bool VersionTableSection<ELFT>::empty() const {
- return !In<ELFT>::VerDef && In<ELFT>::VerNeed->empty();
+ return !In.VerDef && InX<ELFT>::VerNeed->empty();
}
template <class ELFT>
@@ -2729,7 +2793,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
// to create one by adding it to our needed list and creating a dynstr entry
// for the soname.
if (File.VerdefMap.empty())
- Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)});
+ Needed.push_back({&File, In.DynStrTab->addString(File.SoName)});
const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex];
typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver];
@@ -2737,8 +2801,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) {
// prepare to create one by allocating a version identifier and creating a
// dynstr entry for the version name.
if (NV.Index == 0) {
- NV.StrTab = InX::DynStrTab->addString(File.getStringTable().data() +
- Ver->getAux()->vda_name);
+ NV.StrTab = In.DynStrTab->addString(File.getStringTable().data() +
+ Ver->getAux()->vda_name);
NV.Index = NextIndex++;
}
SS->VersionId = NV.Index;
@@ -2780,7 +2844,8 @@ template <class ELFT> void VersionNeedSection<ELFT>::writeTo(uint8_t *Buf) {
}
template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
- getParent()->Link = InX::DynStrTab->getParent()->SectionIndex;
+ if (OutputSection *Sec = In.DynStrTab->getParent())
+ getParent()->Link = Sec->SectionIndex;
getParent()->Info = Needed.size();
}
@@ -2896,12 +2961,6 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name,
return make<MergeNoTailSection>(Name, Type, Flags, Alignment);
}
-// 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().
@@ -2929,8 +2988,10 @@ void elf::mergeSections() {
// We do not want to handle sections that are not alive, so just remove
// them instead of trying to merge.
- if (!MS->Live)
+ if (!MS->Live) {
+ S = nullptr;
continue;
+ }
StringRef OutsecName = getOutputSectionName(MS);
uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);
@@ -3038,34 +3099,54 @@ bool ThunkSection::assignOffsets() {
return Changed;
}
-InputSection *InX::ARMAttributes;
-BssSection *InX::Bss;
-BssSection *InX::BssRelRo;
-BuildIdSection *InX::BuildId;
-EhFrameHeader *InX::EhFrameHdr;
-EhFrameSection *InX::EhFrame;
-SyntheticSection *InX::Dynamic;
-StringTableSection *InX::DynStrTab;
-SymbolTableBaseSection *InX::DynSymTab;
-InputSection *InX::Interp;
-GdbIndexSection *InX::GdbIndex;
-GotSection *InX::Got;
-GotPltSection *InX::GotPlt;
-GnuHashTableSection *InX::GnuHashTab;
-HashTableSection *InX::HashTab;
-IgotPltSection *InX::IgotPlt;
-MipsGotSection *InX::MipsGot;
-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;
-SymtabShndxSection *InX::SymTabShndx;
+// If linking position-dependent code then the table will store the addresses
+// directly in the binary so the section has type SHT_PROGBITS. If linking
+// position-independent code the section has type SHT_NOBITS since it will be
+// allocated and filled in by the dynamic linker.
+PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
+ : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+ Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
+ ".branch_lt") {}
+
+void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
+ assert(Sym.PPC64BranchltIndex == 0xffff);
+ Sym.PPC64BranchltIndex = Entries.size();
+ Entries.push_back(&Sym);
+}
+
+size_t PPC64LongBranchTargetSection::getSize() const {
+ return Entries.size() * 8;
+}
+
+void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
+ assert(Target->GotPltEntrySize == 8);
+ // If linking non-pic we have the final addresses of the targets and they get
+ // written to the table directly. For pic the dynamic linker will allocate
+ // the section and fill it it.
+ if (Config->Pic)
+ return;
+
+ for (const Symbol *Sym : Entries) {
+ assert(Sym->getVA());
+ // Need calls to branch to the local entry-point since a long-branch
+ // must be a local-call.
+ write64(Buf,
+ Sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(Sym->StOther));
+ Buf += Target->GotPltEntrySize;
+ }
+}
+
+bool PPC64LongBranchTargetSection::empty() const {
+ // `removeUnusedSyntheticSections()` is called before thunk allocation which
+ // is too early to determine if this section will be empty or not. We need
+ // Finalized to keep the section alive until after thunk creation. Finalized
+ // only gets set to true once `finalizeSections()` is called after thunk
+ // creation. Becuase of this, if we don't create any long-branch thunks we end
+ // up with an empty .branch_lt section in the binary.
+ return Finalized && Entries.empty();
+}
+
+InStruct elf::In;
template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
@@ -3141,8 +3222,3 @@ template class elf::VersionNeedSection<ELF32LE>;
template class elf::VersionNeedSection<ELF32BE>;
template class elf::VersionNeedSection<ELF64LE>;
template class elf::VersionNeedSection<ELF64BE>;
-
-template class elf::VersionDefinitionSection<ELF32LE>;
-template class elf::VersionDefinitionSection<ELF32BE>;
-template class elf::VersionDefinitionSection<ELF64LE>;
-template class elf::VersionDefinitionSection<ELF64BE>;
diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h
index a780c6631374..6fc40d355d5e 100644
--- a/ELF/SyntheticSections.h
+++ b/ELF/SyntheticSections.h
@@ -21,8 +21,8 @@
#ifndef LLD_ELF_SYNTHETIC_SECTION_H
#define LLD_ELF_SYNTHETIC_SECTION_H
+#include "DWARF.h"
#include "EhFrame.h"
-#include "GdbIndex.h"
#include "InputSection.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
@@ -50,8 +50,6 @@ public:
// If the section has the SHF_ALLOC flag and the size may be changed if
// thunks are added, update the section size.
virtual bool updateAllocSize() { return false; }
- // If any additional finalization of contents are needed post thunk creation.
- virtual void postThunkContents() {}
virtual bool empty() const { return false; }
static bool classof(const SectionBase *D) {
@@ -137,6 +135,15 @@ protected:
uint64_t Size = 0;
};
+// .note.GNU-stack section.
+class GnuStackSection : public SyntheticSection {
+public:
+ GnuStackSection()
+ : SyntheticSection(0, llvm::ELF::SHT_PROGBITS, 1, ".note.GNU-stack") {}
+ void writeTo(uint8_t *Buf) override {}
+ size_t getSize() const override { return 0; }
+};
+
// .note.gnu.build-id section.
class BuildIdSection : public SyntheticSection {
// First 16 bytes are a header.
@@ -163,7 +170,9 @@ private:
class BssSection final : public SyntheticSection {
public:
BssSection(StringRef Name, uint64_t Size, uint32_t Alignment);
- void writeTo(uint8_t *) override {}
+ void writeTo(uint8_t *) override {
+ llvm_unreachable("unexpected writeTo() call for SHT_NOBITS section");
+ }
bool empty() const override { return getSize() == 0; }
size_t getSize() const override { return Size; }
@@ -300,8 +309,6 @@ private:
uint64_t Size = 0;
- size_t LocalEntriesNum = 0;
-
// Symbol and addend.
typedef std::pair<Symbol *, int64_t> GotEntry;
@@ -333,8 +340,6 @@ private:
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.
@@ -529,6 +534,7 @@ struct RelativeReloc {
class RelrBaseSection : public SyntheticSection {
public:
RelrBaseSection();
+ bool empty() const override { return Relocs.empty(); }
std::vector<RelativeReloc> Relocs;
};
@@ -561,7 +567,6 @@ class SymbolTableBaseSection : public SyntheticSection {
public:
SymbolTableBaseSection(StringTableSection &StrTabSec);
void finalizeContents() override;
- void postThunkContents() override;
size_t getSize() const override { return getNumSymbols() * Entsize; }
void addSymbol(Symbol *Sym);
unsigned getNumSymbols() const { return Symbols.size() + 1; }
@@ -569,6 +574,8 @@ public:
ArrayRef<SymbolTableEntry> getSymbols() const { return Symbols; }
protected:
+ void sortSymTabSymbols();
+
// A vector of symbols and their string table offsets.
std::vector<SymbolTableEntry> Symbols;
@@ -612,7 +619,8 @@ public:
void addSymbols(std::vector<SymbolTableEntry> &Symbols);
private:
- enum { Shift2 = 6 };
+ // See the comment in writeBloomFilter.
+ enum { Shift2 = 26 };
void writeBloomFilter(uint8_t *Buf);
void writeHashTable(uint8_t *Buf);
@@ -652,13 +660,13 @@ public:
size_t getSize() const override;
bool empty() const override { return Entries.empty(); }
void addSymbols();
-
template <class ELFT> void addEntry(Symbol &Sym);
+ size_t HeaderSize;
+
private:
unsigned getPltRelocOff() const;
std::vector<std::pair<const Symbol *, unsigned>> Entries;
- size_t HeaderSize;
bool IsIplt;
};
@@ -676,9 +684,9 @@ public:
uint64_t CuLength;
};
- struct NameTypeEntry {
+ struct NameAttrEntry {
llvm::CachedHashStringRef Name;
- uint32_t Type;
+ uint32_t CuIndexAndAttrs;
};
struct GdbChunk {
@@ -748,11 +756,7 @@ public:
// shall be contained in the DT_VERDEFNUM entry of the .dynamic section.
// The section shall contain an array of Elf_Verdef structures, optionally
// followed by an array of Elf_Verdaux structures.
-template <class ELFT>
class VersionDefinitionSection final : public SyntheticSection {
- typedef typename ELFT::Verdef Elf_Verdef;
- typedef typename ELFT::Verdaux Elf_Verdaux;
-
public:
VersionDefinitionSection();
void finalizeContents() override;
@@ -760,6 +764,7 @@ public:
void writeTo(uint8_t *Buf) override;
private:
+ enum { EntrySize = 28 };
void writeOne(uint8_t *Buf, uint32_t Index, StringRef Name, size_t NameOff);
unsigned FileDefNameOff;
@@ -773,8 +778,6 @@ private:
// the own object or in any of the dependencies.
template <class ELFT>
class VersionTableSection final : public SyntheticSection {
- typedef typename ELFT::Versym Elf_Versym;
-
public:
VersionTableSection();
void finalizeContents() override;
@@ -964,9 +967,27 @@ private:
size_t Size = 0;
};
+// This section is used to store the addresses of functions that are called
+// in range-extending thunks on PowerPC64. When producing position dependant
+// code the addresses are link-time constants and the table is written out to
+// the binary. When producing position-dependant code the table is allocated and
+// filled in by the dynamic linker.
+class PPC64LongBranchTargetSection final : public SyntheticSection {
+public:
+ PPC64LongBranchTargetSection();
+ void addEntry(Symbol &Sym);
+ size_t getSize() const override;
+ void writeTo(uint8_t *Buf) override;
+ bool empty() const override;
+ void finalizeContents() override { Finalized = true; }
+
+private:
+ std::vector<const Symbol *> Entries;
+ bool Finalized = false;
+};
+
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
-void decompressSections();
template <class ELFT> void splitSections();
void mergeSections();
@@ -974,46 +995,48 @@ 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 {
- static InputSection *ARMAttributes;
- static BssSection *Bss;
- static BssSection *BssRelRo;
- static BuildIdSection *BuildId;
- static EhFrameHeader *EhFrameHdr;
- static EhFrameSection *EhFrame;
- static SyntheticSection *Dynamic;
- static StringTableSection *DynStrTab;
- static SymbolTableBaseSection *DynSymTab;
- static GnuHashTableSection *GnuHashTab;
- static HashTableSection *HashTab;
- static InputSection *Interp;
- static GdbIndexSection *GdbIndex;
- static GotSection *Got;
- static GotPltSection *GotPlt;
- static IgotPltSection *IgotPlt;
- static MipsGotSection *MipsGot;
- static MipsRldMapSection *MipsRldMap;
- static PltSection *Plt;
- static PltSection *Iplt;
- static RelocationBaseSection *RelaDyn;
- static RelrBaseSection *RelrDyn;
- static RelocationBaseSection *RelaPlt;
- static RelocationBaseSection *RelaIplt;
- static StringTableSection *ShStrTab;
- static StringTableSection *StrTab;
- static SymbolTableBaseSection *SymTab;
- static SymtabShndxSection* SymTabShndx;
-};
-
-template <class ELFT> struct In {
- static VersionDefinitionSection<ELFT> *VerDef;
+struct InStruct {
+ InputSection *ARMAttributes;
+ BssSection *Bss;
+ BssSection *BssRelRo;
+ BuildIdSection *BuildId;
+ EhFrameHeader *EhFrameHdr;
+ EhFrameSection *EhFrame;
+ SyntheticSection *Dynamic;
+ StringTableSection *DynStrTab;
+ SymbolTableBaseSection *DynSymTab;
+ GnuHashTableSection *GnuHashTab;
+ HashTableSection *HashTab;
+ InputSection *Interp;
+ GdbIndexSection *GdbIndex;
+ GotSection *Got;
+ GotPltSection *GotPlt;
+ IgotPltSection *IgotPlt;
+ PPC64LongBranchTargetSection *PPC64LongBranchTarget;
+ MipsGotSection *MipsGot;
+ MipsRldMapSection *MipsRldMap;
+ PltSection *Plt;
+ PltSection *Iplt;
+ RelocationBaseSection *RelaDyn;
+ RelrBaseSection *RelrDyn;
+ RelocationBaseSection *RelaPlt;
+ RelocationBaseSection *RelaIplt;
+ StringTableSection *ShStrTab;
+ StringTableSection *StrTab;
+ SymbolTableBaseSection *SymTab;
+ SymtabShndxSection *SymTabShndx;
+ VersionDefinitionSection *VerDef;
+};
+
+extern InStruct In;
+
+template <class ELFT> struct InX {
static VersionTableSection<ELFT> *VerSym;
static VersionNeedSection<ELFT> *VerNeed;
};
-template <class ELFT> VersionDefinitionSection<ELFT> *In<ELFT>::VerDef;
-template <class ELFT> VersionTableSection<ELFT> *In<ELFT>::VerSym;
-template <class ELFT> VersionNeedSection<ELFT> *In<ELFT>::VerNeed;
+template <class ELFT> VersionTableSection<ELFT> *InX<ELFT>::VerSym;
+template <class ELFT> VersionNeedSection<ELFT> *InX<ELFT>::VerNeed;
} // namespace elf
} // namespace lld
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 815f3a045551..01073a62cfd6 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -73,12 +73,16 @@ TargetInfo *elf::getTarget() {
case ELF64BEKind:
return getMipsTargetInfo<ELF64BE>();
default:
- fatal("unsupported MIPS target");
+ llvm_unreachable("unsupported MIPS target");
}
+ case EM_MSP430:
+ return getMSP430TargetInfo();
case EM_PPC:
return getPPCTargetInfo();
case EM_PPC64:
return getPPC64TargetInfo();
+ case EM_RISCV:
+ return getRISCVTargetInfo();
case EM_SPARCV9:
return getSPARCV9TargetInfo();
case EM_X86_64:
@@ -86,7 +90,7 @@ TargetInfo *elf::getTarget() {
return getX32TargetInfo();
return getX86_64TargetInfo();
}
- fatal("unknown target machine");
+ llvm_unreachable("unknown target machine");
}
template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) {
@@ -130,12 +134,11 @@ bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
return false;
}
-bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc,
- uint8_t *End) const {
+bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) 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 82c7b8f7b6c5..685ad05ecd66 100644
--- a/ELF/Target.h
+++ b/ELF/Target.h
@@ -13,6 +13,8 @@
#include "InputSection.h"
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/ELF.h"
+#include "llvm/Support/MathExtras.h"
+#include <array>
namespace lld {
std::string toString(elf::RelType Type);
@@ -43,10 +45,6 @@ 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 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
@@ -60,11 +58,18 @@ public:
const InputFile *File, uint64_t BranchAddr,
const Symbol &S) const;
+ // On systems with range extensions we place collections of Thunks at
+ // regular spacings that enable the majority of branches reach the Thunks.
+ // a value of 0 means range extension thunks are not supported.
+ virtual uint32_t getThunkSectionSpacing() const { return 0; }
+
// 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;
+ // The symbols st_other flags are needed on PowerPC64 for determining the
+ // offset to the split-stack prologue.
+ virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, uint8_t *End,
+ uint8_t StOther) const;
// Return true if we can reach Dst from Src with Relocation RelocType
virtual bool inBranchRange(RelType Type, uint64_t Src,
@@ -87,12 +92,9 @@ public:
// 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.
- uint32_t ThunkSectionSpacing = 0;
-
RelType CopyRel;
RelType GotRel;
+ RelType NoneRel;
RelType PltRel;
RelType RelativeRel;
RelType IRelativeRel;
@@ -112,20 +114,16 @@ public:
// 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
// executable OutputSections.
- uint32_t TrapInstr = 0;
+ std::array<uint8_t, 4> TrapInstr;
+
+ // If a target needs to rewrite calls to __morestack to instead call
+ // __morestack_non_split when a split-stack enabled caller calls a
+ // non-split-stack callee this will return true. Otherwise returns false.
+ bool NeedsMoreStackNonSplit = true;
virtual RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
RelExpr Expr) const;
@@ -148,8 +146,10 @@ TargetInfo *getAMDGPUTargetInfo();
TargetInfo *getARMTargetInfo();
TargetInfo *getAVRTargetInfo();
TargetInfo *getHexagonTargetInfo();
+TargetInfo *getMSP430TargetInfo();
TargetInfo *getPPC64TargetInfo();
TargetInfo *getPPCTargetInfo();
+TargetInfo *getRISCVTargetInfo();
TargetInfo *getSPARCV9TargetInfo();
TargetInfo *getX32TargetInfo();
TargetInfo *getX86TargetInfo();
@@ -168,6 +168,15 @@ static inline std::string getErrorLocation(const uint8_t *Loc) {
return getErrorPlace(Loc).Loc;
}
+// In the PowerPC64 Elf V2 abi a function can have 2 entry points. The first is
+// a global entry point (GEP) which typically is used to intiailzie the TOC
+// pointer in general purpose register 2. The second is a local entry
+// point (LEP) which bypasses the TOC pointer initialization code. The
+// offset between GEP and LEP is encoded in a function's st_other flags.
+// This function will return the offset (in bytes) from the global entry-point
+// to the local entry-point.
+unsigned getPPC64GlobalEntryToLocalEntryOffset(uint8_t StOther);
+
uint64_t getPPC64TocBase();
uint64_t getAArch64Page(uint64_t Expr);
@@ -184,19 +193,18 @@ static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V,
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);
+ errorOrWarn(ErrPlace.Loc + "relocation " + lld::toString(Type) +
+ " out of range: " + V.str() + " is not in [" + Twine(Min).str() +
+ ", " + Twine(Max).str() + "]" + Hint);
}
-// 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);
+inline unsigned getPltEntryOffset(unsigned Idx) {
+ return Target->PltHeaderSize + Target->PltEntrySize * Idx;
}
// 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))
+ if (V != llvm::SignExtend64(V, N))
reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N));
}
@@ -210,7 +218,7 @@ inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) {
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)
+ if (V != (uint64_t)llvm::SignExtend64(V, N) && (V >> N) != 0)
reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N),
llvm::maxIntN(N));
}
diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp
index 2cd7e51ae357..95b57dc0db42 100644
--- a/ELF/Thunks.cpp
+++ b/ELF/Thunks.cpp
@@ -159,6 +159,50 @@ public:
void addSymbols(ThunkSection &IS) override;
};
+// Implementations of Thunks for older Arm architectures that do not support
+// the movt/movw instructions. These thunks require at least Architecture v5
+// as used on processors such as the Arm926ej-s. There are no Thumb entry
+// points as there is no Thumb branch instruction on these architecture that
+// can result in a thunk
+class ARMV5ABSLongThunk final : public ARMThunk {
+public:
+ ARMV5ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 8; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+class ARMV5PILongThunk final : public ARMThunk {
+public:
+ ARMV5PILongThunk(Symbol &Dest) : ARMThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+ bool isCompatibleWith(uint32_t RelocType) const override;
+};
+
+// Implementations of Thunks for Arm v6-M. Only Thumb instructions are permitted
+class ThumbV6MABSLongThunk final : public ThumbThunk {
+public:
+ ThumbV6MABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 12; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
+class ThumbV6MPILongThunk final : public ThumbThunk {
+public:
+ ThumbV6MPILongThunk(Symbol &Dest) : ThumbThunk(Dest) {}
+
+ uint32_t sizeLong() override { return 16; }
+ void writeLong(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+};
+
// MIPS LA25 thunk
class MipsThunk final : public Thunk {
public:
@@ -209,6 +253,46 @@ public:
void addSymbols(ThunkSection &IS) override;
};
+// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
+// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
+// larger then that we need to emit a long-branch thunk. The target address
+// of the callee is stored in a table to be accessed TOC-relative. Since the
+// call must be local (a non-local call will have a PltCallStub instead) the
+// table stores the address of the callee's local entry point. For
+// position-independent code a corresponding relative dynamic relocation is
+// used.
+class PPC64LongBranchThunk : public Thunk {
+public:
+ uint32_t size() override { return 16; }
+ void writeTo(uint8_t *Buf) override;
+ void addSymbols(ThunkSection &IS) override;
+
+protected:
+ PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {}
+};
+
+class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ assert(!Dest.IsPreemptible);
+ if (Dest.isInPPC64Branchlt())
+ return;
+
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget,
+ Dest.getPPC64LongBranchOffset(), true, &Dest,
+ getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)});
+ }
+};
+
+class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
+public:
+ PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+ if (!Dest.isInPPC64Branchlt())
+ In.PPC64LongBranchTarget->addEntry(Dest);
+ }
+};
+
} // end anonymous namespace
Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
@@ -395,12 +479,12 @@ 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)
- 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
- 0x1c, 0xff, 0x2f, 0xe1, // bx r12
+ 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
};
uint64_t S = getARMThunkDestVA(Destination);
uint64_t P = getThunkTargetSym()->getVA();
- uint64_t Offset = S - P - 16;
+ int64_t Offset = S - P - 16;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset);
Target->relocateOne(Buf + 4, R_ARM_MOVT_PREL, Offset);
@@ -416,12 +500,12 @@ 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)
- 0xfc, 0x44, // L1: add r12, pc
- 0x60, 0x47, // bx r12
+ 0xfc, 0x44, // L1: add ip, pc
+ 0x60, 0x47, // bx ip
};
uint64_t S = getARMThunkDestVA(Destination);
uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
- uint64_t Offset = S - P - 12;
+ int64_t Offset = S - P - 12;
memcpy(Buf, Data, sizeof(Data));
Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset);
Target->relocateOne(Buf + 4, R_ARM_THM_MOVT_PREL, Offset);
@@ -433,6 +517,102 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) {
addSymbol("$t", STT_NOTYPE, 0, IS);
}
+void ARMV5ABSLongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xf0, 0x1f, 0xe5, // ldr pc, [pc,#-4] ; L1
+ 0x00, 0x00, 0x00, 0x00, // L1: .word S
+ };
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 4, R_ARM_ABS32, getARMThunkDestVA(Destination));
+}
+
+void ARMV5ABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMv5ABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 4, IS);
+}
+
+bool ARMV5ABSLongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ARMV5PILongThunk::writeLong(uint8_t *Buf) {
+ const uint8_t Data[] = {
+ 0x04, 0xc0, 0x9f, 0xe5, // P: ldr ip, [pc,#4] ; L2
+ 0x0c, 0xc0, 0x8f, 0xe0, // L1: add ip, pc, ip
+ 0x1c, 0xff, 0x2f, 0xe1, // bx ip
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 8)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ARMV5PILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__ARMV5PILongThunk_" + Destination.getName()), STT_FUNC,
+ 0, IS);
+ addSymbol("$a", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
+bool ARMV5PILongThunk::isCompatibleWith(uint32_t RelocType) const {
+ // Thumb branch relocations can't use BLX
+ return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24;
+}
+
+void ThumbV6MABSLongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is r12 we must instead spill a low register
+ // to the stack to use as a scratch register. We push r1 even though we
+ // don't need to get some space to use for the return address.
+ const uint8_t Data[] = {
+ 0x03, 0xb4, // push {r0, r1} ; Obtain scratch registers
+ 0x01, 0x48, // ldr r0, [pc, #4] ; L1
+ 0x01, 0x90, // str r0, [sp, #4] ; SP + 4 = S
+ 0x01, 0xbd, // pop {r0, pc} ; restore r0 and branch to dest
+ 0x00, 0x00, 0x00, 0x00 // L1: .word S
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 8, R_ARM_ABS32, S);
+}
+
+void ThumbV6MABSLongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MABSLongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 8, IS);
+}
+
+void ThumbV6MPILongThunk::writeLong(uint8_t *Buf) {
+ // Most Thumb instructions cannot access the high registers r8 - r15. As the
+ // only register we can corrupt is ip (r12) we must instead spill a low
+ // register to the stack to use as a scratch register.
+ const uint8_t Data[] = {
+ 0x01, 0xb4, // P: push {r0} ; Obtain scratch register
+ 0x02, 0x48, // ldr r0, [pc, #8] ; L2
+ 0x84, 0x46, // mov ip, r0 ; high to low register
+ 0x01, 0xbc, // pop {r0} ; restore scratch register
+ 0xe7, 0x44, // L1: add pc, ip ; transfer control
+ 0xc0, 0x46, // nop ; pad to 4-byte boundary
+ 0x00, 0x00, 0x00, 0x00, // L2: .word S - (P + (L1 - P) + 4)
+ };
+ uint64_t S = getARMThunkDestVA(Destination);
+ uint64_t P = getThunkTargetSym()->getVA() & ~0x1;
+ memcpy(Buf, Data, sizeof(Data));
+ Target->relocateOne(Buf + 12, R_ARM_REL32, S - P - 12);
+}
+
+void ThumbV6MPILongThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__Thumbv6MPILongThunk_" + Destination.getName()),
+ STT_FUNC, 1, IS);
+ addSymbol("$t", STT_NOTYPE, 0, IS);
+ addSymbol("$d", STT_NOTYPE, 12, IS);
+}
+
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
void MipsThunk::writeTo(uint8_t *Buf) {
uint64_t S = Destination.getVA();
@@ -502,17 +682,21 @@ 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;
+static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) {
+ uint16_t OffHa = (Offset + 0x8000) >> 16;
+ uint16_t OffLo = Offset & 0xffff;
- 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
+ write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa
+ write32(Buf + 4, 0xe98c0000 | OffLo); // ld r12, OffLo(r12)
+ write32(Buf + 8, 0x7d8903a6); // mtctr r12
+ write32(Buf + 12, 0x4e800420); // bctr
+}
+
+void PPC64PltCallStub::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase();
+ // Save the TOC pointer to the save-slot reserved in the call frame.
+ write32(Buf + 0, 0xf8410018); // std r2,24(r1)
+ writePPCLoadAndBranch(Buf + 4, Offset);
}
void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
@@ -521,6 +705,16 @@ void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
S->NeedsTocRestore = true;
}
+void PPC64LongBranchThunk::writeTo(uint8_t *Buf) {
+ int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase();
+ writePPCLoadAndBranch(Buf, Offset);
+}
+
+void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) {
+ addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0,
+ IS);
+}
+
Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
Thunk::~Thunk() = default;
@@ -534,10 +728,67 @@ static Thunk *addThunkAArch64(RelType Type, Symbol &S) {
}
// Creates a thunk for Thumb-ARM interworking.
+// Arm Architectures v5 and v6 do not support Thumb2 technology. This means
+// - MOVT and MOVW instructions cannot be used
+// - Only Thumb relocation that can generate a Thunk is a BL, this can always
+// be transformed into a BLX
+static Thunk *addThunkPreArmv7(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_PC24:
+ case R_ARM_PLT32:
+ case R_ARM_JUMP24:
+ case R_ARM_CALL:
+ case R_ARM_THM_CALL:
+ if (Config->Pic)
+ return make<ARMV5PILongThunk>(S);
+ return make<ARMV5ABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv5 or Armv6 targets");
+}
+
+// Create a thunk for Thumb long branch on V6-M.
+// Arm Architecture v6-M only supports Thumb instructions. This means
+// - MOVT and MOVW instructions cannot be used.
+// - Only a limited number of instructions can access registers r8 and above
+// - No interworking support is needed (all Thumb).
+static Thunk *addThunkV6M(RelType Reloc, Symbol &S) {
+ switch (Reloc) {
+ case R_ARM_THM_JUMP19:
+ case R_ARM_THM_JUMP24:
+ case R_ARM_THM_CALL:
+ if (Config->Pic)
+ return make<ThumbV6MPILongThunk>(S);
+ return make<ThumbV6MABSLongThunk>(S);
+ }
+ fatal("relocation " + toString(Reloc) + " to " + toString(S) +
+ " not supported for Armv6-M targets");
+}
+
+// Creates a thunk for Thumb-ARM interworking or branch range extension.
static Thunk *addThunkArm(RelType Reloc, Symbol &S) {
- // ARM relocations need ARM to Thumb interworking Thunks.
- // Thumb relocations need Thumb to ARM relocations.
- // Use position independent Thunks if we require position independent code.
+ // Decide which Thunk is needed based on:
+ // Available instruction set
+ // - An Arm Thunk can only be used if Arm state is available.
+ // - A Thumb Thunk can only be used if Thumb state is available.
+ // - Can only use a Thunk if it uses instructions that the Target supports.
+ // Relocation is branch or branch and link
+ // - Branch instructions cannot change state, can only select Thunk that
+ // starts in the same state as the caller.
+ // - Branch and link relocations can change state, can select Thunks from
+ // either Arm or Thumb.
+ // Position independent Thunks if we require position independent code.
+
+ // Handle architectures that have restrictions on the instructions that they
+ // can use in Thunks. The flags below are set by reading the BuildAttributes
+ // of the input objects. InputFiles.cpp contains the mapping from ARM
+ // architecture to flag.
+ if (!Config->ARMHasMovtMovw) {
+ if (!Config->ARMJ1J2BranchEncoding)
+ return addThunkPreArmv7(Reloc, S);
+ return addThunkV6M(Reloc, S);
+ }
+
switch (Reloc) {
case R_ARM_PC24:
case R_ARM_PLT32:
@@ -565,9 +816,14 @@ static Thunk *addThunkMips(RelType Type, Symbol &S) {
}
static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
- if (Type == R_PPC64_REL24)
+ assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk");
+ if (S.isInPlt())
return make<PPC64PltCallStub>(S);
- fatal("unexpected relocation type");
+
+ if (Config->Pic)
+ return make<PPC64PILongBranchThunk>(S);
+
+ return make<PPC64PDLongBranchThunk>(S);
}
Thunk *addThunk(RelType Type, Symbol &S) {
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 73a97380b54b..17f4c7961d30 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -53,8 +53,10 @@ private:
void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn);
void sortSections();
void resolveShfLinkOrder();
+ void maybeAddThunks();
void sortInputSections();
void finalizeSections();
+ void checkExecuteOnly();
void setReservedSymbolSections();
std::vector<PhdrEntry *> createPhdrs();
@@ -77,7 +79,6 @@ private:
void addRelIpltSymbols();
void addStartEndSymbols();
void addStartStopSymbols(OutputSection *Sec);
- uint64_t getEntryAddr();
std::vector<PhdrEntry *> Phdrs;
@@ -114,18 +115,16 @@ StringRef elf::getOutputSectionName(const InputSectionBase *S) {
// for instance.
if (Config->ZKeepTextSectionPrefix)
for (StringRef V :
- {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) {
+ {".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."}) {
+ ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."})
if (isSectionPrefix(V, S->Name))
return V.drop_back();
- }
// CommonSection is identified as "COMMON" in linker scripts.
// By default, it should go to .bss section.
@@ -159,7 +158,7 @@ template <class ELFT> static void combineEhFrameSections() {
if (!ES || !ES->Live)
continue;
- InX::EhFrame->addSection<ELFT>(ES);
+ In.EhFrame->addSection<ELFT>(ES);
S = nullptr;
}
@@ -173,10 +172,14 @@ static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec,
Symbol *S = Symtab->find(Name);
if (!S || S->isDefined())
return nullptr;
- Symbol *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val,
- /*Size=*/0, Binding, Sec,
- /*File=*/nullptr);
- return cast<Defined>(Sym);
+ return Symtab->addDefined(Name, StOther, STT_NOTYPE, Val,
+ /*Size=*/0, Binding, Sec,
+ /*File=*/nullptr);
+}
+
+static Defined *addAbsolute(StringRef Name) {
+ return Symtab->addDefined(Name, STV_HIDDEN, STT_NOTYPE, 0, 0, STB_GLOBAL,
+ nullptr, nullptr);
}
// The linker is expected to define some symbols depending on
@@ -188,21 +191,19 @@ void elf::addReservedSymbols() {
// to GOT. Default offset is 0x7ff0.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsGp = addAbsolute("_gp");
// On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
// start of function and 'gp' pointer into GOT.
if (Symtab->find("_gp_disp"))
- ElfSym::MipsGpDisp =
- Symtab->addAbsolute("_gp_disp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsGpDisp = addAbsolute("_gp_disp");
// The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
// pointer. This symbol is used in the code generated by .cpload pseudo-op
// in case of using -mno-shared option.
// https://sourceware.org/ml/binutils/2004-12/msg00094.html
if (Symtab->find("__gnu_local_gp"))
- ElfSym::MipsLocalGp =
- Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL);
+ ElfSym::MipsLocalGp = addAbsolute("__gnu_local_gp");
}
// The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which
@@ -211,9 +212,20 @@ void elf::addReservedSymbols() {
// _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(
- (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_",
- Out::ElfHeader, Target->GotBaseSymOff);
+ // We do not allow _GLOBAL_OFFSET_TABLE_ to be defined by input objects as the
+ // correctness of some relocations depends on its value.
+ StringRef GotTableSymName =
+ (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_";
+ if (Symbol *S = Symtab->find(GotTableSymName)) {
+ if (S->isDefined())
+ error(toString(S->File) + " cannot redefine linker defined symbol '" +
+ GotTableSymName + "'");
+ else
+ ElfSym::GlobalOffsetTable = Symtab->addDefined(
+ GotTableSymName, STV_HIDDEN, STT_NOTYPE, Target->GotBaseSymOff,
+ /*Size=*/0, STB_GLOBAL, Out::ElfHeader,
+ /*File=*/nullptr);
+ }
// __ehdr_start is the location of ELF file headers. Note that we define
// this symbol unconditionally even when using a linker script, which
@@ -263,54 +275,52 @@ template <class ELFT> static void createSyntheticSections() {
auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); };
- InX::DynStrTab = make<StringTableSection>(".dynstr", true);
- InX::Dynamic = make<DynamicSection<ELFT>>();
+ In.DynStrTab = make<StringTableSection>(".dynstr", true);
+ In.Dynamic = make<DynamicSection<ELFT>>();
if (Config->AndroidPackDynRelocs) {
- InX::RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
+ In.RelaDyn = make<AndroidPackedRelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn");
} else {
- InX::RelaDyn = make<RelocationSection<ELFT>>(
+ In.RelaDyn = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
}
- InX::ShStrTab = make<StringTableSection>(".shstrtab", false);
+ In.ShStrTab = make<StringTableSection>(".shstrtab", false);
Out::ProgramHeaders = make<OutputSection>("", 0, SHF_ALLOC);
Out::ProgramHeaders->Alignment = Config->Wordsize;
if (needsInterpSection()) {
- InX::Interp = createInterpSection();
- Add(InX::Interp);
- } else {
- InX::Interp = nullptr;
+ In.Interp = createInterpSection();
+ Add(In.Interp);
}
if (Config->Strip != StripPolicy::All) {
- InX::StrTab = make<StringTableSection>(".strtab", false);
- InX::SymTab = make<SymbolTableSection<ELFT>>(*InX::StrTab);
- InX::SymTabShndx = make<SymtabShndxSection>();
+ In.StrTab = make<StringTableSection>(".strtab", false);
+ In.SymTab = make<SymbolTableSection<ELFT>>(*In.StrTab);
+ In.SymTabShndx = make<SymtabShndxSection>();
}
if (Config->BuildId != BuildIdKind::None) {
- InX::BuildId = make<BuildIdSection>();
- Add(InX::BuildId);
+ In.BuildId = make<BuildIdSection>();
+ Add(In.BuildId);
}
- InX::Bss = make<BssSection>(".bss", 0, 1);
- Add(InX::Bss);
+ In.Bss = make<BssSection>(".bss", 0, 1);
+ Add(In.Bss);
// 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 =
+ In.BssRelRo =
make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
- Add(InX::BssRelRo);
+ Add(In.BssRelRo);
// Add MIPS-specific sections.
if (Config->EMachine == EM_MIPS) {
if (!Config->Shared && Config->HasDynSymTab) {
- InX::MipsRldMap = make<MipsRldMapSection>();
- Add(InX::MipsRldMap);
+ In.MipsRldMap = make<MipsRldMapSection>();
+ Add(In.MipsRldMap);
}
if (auto *Sec = MipsAbiFlagsSection<ELFT>::create())
Add(Sec);
@@ -321,65 +331,70 @@ template <class ELFT> static void createSyntheticSections() {
}
if (Config->HasDynSymTab) {
- InX::DynSymTab = make<SymbolTableSection<ELFT>>(*InX::DynStrTab);
- Add(InX::DynSymTab);
+ In.DynSymTab = make<SymbolTableSection<ELFT>>(*In.DynStrTab);
+ Add(In.DynSymTab);
- In<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
- Add(In<ELFT>::VerSym);
+ InX<ELFT>::VerSym = make<VersionTableSection<ELFT>>();
+ Add(InX<ELFT>::VerSym);
if (!Config->VersionDefinitions.empty()) {
- In<ELFT>::VerDef = make<VersionDefinitionSection<ELFT>>();
- Add(In<ELFT>::VerDef);
+ In.VerDef = make<VersionDefinitionSection>();
+ Add(In.VerDef);
}
- In<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
- Add(In<ELFT>::VerNeed);
+ InX<ELFT>::VerNeed = make<VersionNeedSection<ELFT>>();
+ Add(InX<ELFT>::VerNeed);
if (Config->GnuHash) {
- InX::GnuHashTab = make<GnuHashTableSection>();
- Add(InX::GnuHashTab);
+ In.GnuHashTab = make<GnuHashTableSection>();
+ Add(In.GnuHashTab);
}
if (Config->SysvHash) {
- InX::HashTab = make<HashTableSection>();
- Add(InX::HashTab);
+ In.HashTab = make<HashTableSection>();
+ Add(In.HashTab);
}
- Add(InX::Dynamic);
- Add(InX::DynStrTab);
- Add(InX::RelaDyn);
+ Add(In.Dynamic);
+ Add(In.DynStrTab);
+ Add(In.RelaDyn);
}
if (Config->RelrPackDynRelocs) {
- InX::RelrDyn = make<RelrSection<ELFT>>();
- Add(InX::RelrDyn);
+ In.RelrDyn = make<RelrSection<ELFT>>();
+ Add(In.RelrDyn);
}
// Add .got. MIPS' .got is so different from the other archs,
// it has its own class.
if (Config->EMachine == EM_MIPS) {
- InX::MipsGot = make<MipsGotSection>();
- Add(InX::MipsGot);
+ In.MipsGot = make<MipsGotSection>();
+ Add(In.MipsGot);
} else {
- InX::Got = make<GotSection>();
- Add(InX::Got);
+ In.Got = make<GotSection>();
+ Add(In.Got);
}
- InX::GotPlt = make<GotPltSection>();
- Add(InX::GotPlt);
- InX::IgotPlt = make<IgotPltSection>();
- Add(InX::IgotPlt);
+ if (Config->EMachine == EM_PPC64) {
+ In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>();
+ Add(In.PPC64LongBranchTarget);
+ }
+
+ In.GotPlt = make<GotPltSection>();
+ Add(In.GotPlt);
+ In.IgotPlt = make<IgotPltSection>();
+ Add(In.IgotPlt);
if (Config->GdbIndex) {
- InX::GdbIndex = GdbIndexSection::create<ELFT>();
- Add(InX::GdbIndex);
+ In.GdbIndex = GdbIndexSection::create<ELFT>();
+ Add(In.GdbIndex);
}
// We always need to add rel[a].plt to output if it has entries.
// Even for static linking it can contain R_[*]_IRELATIVE relocations.
- InX::RelaPlt = make<RelocationSection<ELFT>>(
+ In.RelaPlt = make<RelocationSection<ELFT>>(
Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
- Add(InX::RelaPlt);
+ Add(In.RelaPlt);
// The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
// that the IRelative relocations are processed last by the dynamic loader.
@@ -387,34 +402,42 @@ template <class ELFT> static void createSyntheticSections() {
// packing is enabled because that would cause a section type mismatch.
// However, because the Android dynamic loader reads .rel.plt after .rel.dyn,
// we can get the desired behaviour by placing the iplt section in .rel.plt.
- InX::RelaIplt = make<RelocationSection<ELFT>>(
+ In.RelaIplt = make<RelocationSection<ELFT>>(
(Config->EMachine == EM_ARM && !Config->AndroidPackDynRelocs)
? ".rel.dyn"
- : InX::RelaPlt->Name,
+ : In.RelaPlt->Name,
false /*Sort*/);
- Add(InX::RelaIplt);
-
- InX::Plt = make<PltSection>(false);
- Add(InX::Plt);
- InX::Iplt = make<PltSection>(true);
- Add(InX::Iplt);
+ Add(In.RelaIplt);
+
+ In.Plt = make<PltSection>(false);
+ Add(In.Plt);
+ In.Iplt = make<PltSection>(true);
+ Add(In.Iplt);
+
+ // .note.GNU-stack is always added when we are creating a re-linkable
+ // object file. Other linkers are using the presence of this marker
+ // section to control the executable-ness of the stack area, but that
+ // is irrelevant these days. Stack area should always be non-executable
+ // by default. So we emit this section unconditionally.
+ if (Config->Relocatable)
+ Add(make<GnuStackSection>());
if (!Config->Relocatable) {
if (Config->EhFrameHdr) {
- InX::EhFrameHdr = make<EhFrameHeader>();
- Add(InX::EhFrameHdr);
+ In.EhFrameHdr = make<EhFrameHeader>();
+ Add(In.EhFrameHdr);
}
- InX::EhFrame = make<EhFrameSection>();
- Add(InX::EhFrame);
+ In.EhFrame = make<EhFrameSection>();
+ Add(In.EhFrame);
}
- if (InX::SymTab)
- Add(InX::SymTab);
- if (InX::SymTabShndx)
- Add(InX::SymTabShndx);
- Add(InX::ShStrTab);
- if (InX::StrTab)
- Add(InX::StrTab);
+ if (In.SymTab)
+ Add(In.SymTab);
+ if (In.SymTabShndx)
+ Add(In.SymTabShndx);
+ Add(In.ShStrTab);
+ if (In.StrTab)
+ Add(In.StrTab);
if (Config->EMachine == EM_ARM && !Config->Relocatable)
// Add a sentinel to terminate .ARM.exidx. It helps an unwinder
@@ -451,6 +474,7 @@ template <class ELFT> void Writer<ELFT>::run() {
// to the string table, and add entries to .got and .plt.
// finalizeSections does that.
finalizeSections();
+ checkExecuteOnly();
if (errorCount())
return;
@@ -476,10 +500,9 @@ template <class ELFT> void Writer<ELFT>::run() {
setPhdrs();
- if (Config->Relocatable) {
+ if (Config->Relocatable)
for (OutputSection *Sec : OutputSections)
Sec->Addr = 0;
- }
if (Config->CheckSections)
checkSections();
@@ -548,9 +571,11 @@ static bool includeInSymtab(const Symbol &B) {
if (!Sec)
return true;
Sec = Sec->Repl;
+
// Exclude symbols pointing to garbage-collected sections.
if (isa<InputSectionBase>(Sec) && !Sec->Live)
return false;
+
if (auto *S = dyn_cast<MergeInputSection>(Sec))
if (!S->getSectionPiece(D->Value)->Live)
return false;
@@ -562,7 +587,7 @@ static bool includeInSymtab(const Symbol &B) {
// Local symbols are not in the linker's symbol table. This function scans
// each object file's symbol table to copy local symbols to the output.
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
- if (!InX::SymTab)
+ if (!In.SymTab)
return;
for (InputFile *File : ObjectFiles) {
ObjFile<ELFT> *F = cast<ObjFile<ELFT>>(File);
@@ -581,16 +606,16 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
SectionBase *Sec = DR->Section;
if (!shouldKeepInSymtab(Sec, B->getName(), *B))
continue;
- InX::SymTab->addSymbol(B);
+ In.SymTab->addSymbol(B);
}
}
}
+// Create a section symbol for each output section so that we can represent
+// relocations that point to the section. If we know that no relocation is
+// referring to a section (that happens if the section is a synthetic one), we
+// don't create a section symbol for that section.
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
- // Create a section symbol for each output section so that we can represent
- // relocations that point to the section. If we know that no relocation is
- // referring to a section (that happens if the section is a synthetic one), we
- // don't create a section symbol for that section.
for (BaseCommand *Base : Script->SectionCommands) {
auto *Sec = dyn_cast<OutputSection>(Base);
if (!Sec)
@@ -617,7 +642,7 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
auto *Sym =
make<Defined>(IS->File, "", STB_LOCAL, /*StOther=*/0, STT_SECTION,
/*Value=*/0, /*Size=*/0, IS);
- InX::SymTab->addSymbol(Sym);
+ In.SymTab->addSymbol(Sym);
}
}
@@ -662,9 +687,14 @@ static bool isRelroSection(const OutputSection *Sec) {
// .got contains pointers to external symbols. They are resolved by
// the dynamic linker when a module is loaded into memory, and after
// that they are not expected to change. So, it can be in RELRO.
- if (InX::Got && Sec == InX::Got->getParent())
+ if (In.Got && Sec == In.Got->getParent())
return true;
+ // .toc is a GOT-ish section for PowerPC64. Their contents are accessed
+ // through r2 register, which is reserved for that purpose. Since r2 is used
+ // for accessing .got as well, .got and .toc need to be close enough in the
+ // virtual address space. Usually, .toc comes just after .got. Since we place
+ // .got into RELRO, .toc needs to be placed into RELRO too.
if (Sec->Name.equals(".toc"))
return true;
@@ -672,13 +702,13 @@ static bool isRelroSection(const OutputSection *Sec) {
// by default resolved lazily, so we usually cannot put it into RELRO.
// However, if "-z now" is given, the lazy symbol resolution is
// disabled, which enables us to put it into RELRO.
- if (Sec == InX::GotPlt->getParent())
+ if (Sec == In.GotPlt->getParent())
return Config->ZNow;
// .dynamic section contains data for the dynamic linker, and
// there's no need to write to it at runtime, so it's better to put
// it into RELRO.
- if (Sec == InX::Dynamic->getParent())
+ if (Sec == In.Dynamic->getParent())
return true;
// Sections with some special names are put into RELRO. This is a
@@ -700,17 +730,17 @@ static bool isRelroSection(const OutputSection *Sec) {
// * It is easy two see how similar two ranks are (see getRankProximity).
enum RankFlags {
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_NOT_ALLOC = 1 << 17,
+ RF_NOT_INTERP = 1 << 16,
+ RF_NOT_NOTE = 1 << 15,
+ RF_WRITE = 1 << 14,
+ RF_EXEC_WRITE = 1 << 13,
+ RF_EXEC = 1 << 12,
+ RF_RODATA = 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_PPC_NOT_TOCBSS = 1 << 6,
RF_PPC_TOCL = 1 << 5,
RF_PPC_TOC = 1 << 4,
@@ -729,16 +759,24 @@ static unsigned getSectionRank(const OutputSection *Sec) {
return Rank;
Rank |= RF_NOT_ADDR_SET;
+ // Allocatable sections go first to reduce the total PT_LOAD size and
+ // so debug info doesn't change addresses in actual code.
+ if (!(Sec->Flags & SHF_ALLOC))
+ return Rank | RF_NOT_ALLOC;
+
// Put .interp first because some loaders want to see that section
// on the first page of the executable file when loaded into memory.
if (Sec->Name == ".interp")
return Rank;
Rank |= RF_NOT_INTERP;
- // Allocatable sections go first to reduce the total PT_LOAD size and
- // so debug info doesn't change addresses in actual code.
- if (!(Sec->Flags & SHF_ALLOC))
- return Rank | RF_NOT_ALLOC;
+ // Put .note sections (which make up one PT_NOTE) at the beginning so that
+ // they are likely to be included in a core file even if core file size is
+ // limited. In particular, we want a .note.gnu.build-id and a .note.tag to be
+ // included in a core to match core files with executables.
+ if (Sec->Type == SHT_NOTE)
+ return Rank;
+ Rank |= RF_NOT_NOTE;
// Sort sections based on their access permission in the following
// order: R, RX, RWX, RW. This order is based on the following
@@ -802,12 +840,6 @@ 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) {
@@ -850,8 +882,10 @@ static unsigned getSectionRank(const OutputSection *Sec) {
static bool compareSections(const BaseCommand *ACmd, const BaseCommand *BCmd) {
const OutputSection *A = cast<OutputSection>(ACmd);
const OutputSection *B = cast<OutputSection>(BCmd);
+
if (A->SortRank != B->SortRank)
return A->SortRank < B->SortRank;
+
if (!(A->SortRank & RF_NOT_ADDR_SET))
return Config->SectionStartMap.lookup(A->Name) <
Config->SectionStartMap.lookup(B->Name);
@@ -874,14 +908,20 @@ 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 (needsInterpSection())
+ if (Config->Relocatable || 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";
- ElfSym::RelaIpltEnd =
- addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK);
+ // By default, __rela_iplt_{start,end} belong to a dummy section 0
+ // because .rela.plt might be empty and thus removed from output.
+ // We'll override Out::ElfHeader with In.RelaIplt later when we are
+ // sure that .rela.plt exists in output.
+ ElfSym::RelaIpltStart = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
+
+ ElfSym::RelaIpltEnd = addOptionalRegular(
+ Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end",
+ Out::ElfHeader, 0, STV_HIDDEN, STB_WEAK);
}
template <class ELFT>
@@ -895,7 +935,7 @@ void Writer<ELFT>::forEachRelSec(
for (InputSectionBase *IS : InputSections)
if (IS->Live && isa<InputSection>(IS) && (IS->Flags & SHF_ALLOC))
Fn(*IS);
- for (EhInputSection *ES : InX::EhFrame->Sections)
+ for (EhInputSection *ES : In.EhFrame->Sections)
Fn(*ES);
}
@@ -908,15 +948,19 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
if (ElfSym::GlobalOffsetTable) {
// 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;
+ InputSection *GotSection = In.GotPlt;
if (!Target->GotBaseSymInGotPlt)
- GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot)
- : cast<InputSection>(InX::Got);
+ GotSection = In.MipsGot ? cast<InputSection>(In.MipsGot)
+ : cast<InputSection>(In.Got);
ElfSym::GlobalOffsetTable->Section = GotSection;
}
- if (ElfSym::RelaIpltEnd)
- ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize();
+ // .rela_iplt_{start,end} mark the start and the end of .rela.plt section.
+ if (ElfSym::RelaIpltStart && !In.RelaIplt->empty()) {
+ ElfSym::RelaIpltStart->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Section = In.RelaIplt;
+ ElfSym::RelaIpltEnd->Value = In.RelaIplt->getSize();
+ }
PhdrEntry *Last = nullptr;
PhdrEntry *LastRO = nullptr;
@@ -1088,7 +1132,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
SymbolOrderEntry &Ent = It->second;
Ent.Present = true;
- warnUnorderableSymbol(&Sym);
+ maybeWarnUnorderableSymbol(&Sym);
if (auto *D = dyn_cast<Defined>(&Sym)) {
if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) {
@@ -1097,6 +1141,7 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
}
}
};
+
// 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())
@@ -1132,11 +1177,10 @@ sortISDBySectionOrder(InputSectionDescription *ISD,
}
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;
- });
+ llvm::sort(OrderedSections, [&](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
@@ -1166,7 +1210,7 @@ sortISDBySectionOrder(InputSectionDescription *ISD,
// 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()) {
+ if (Target->getThunkSectionSpacing() && !OrderedSections.empty()) {
uint64_t UnorderedPos = 0;
for (; InsPt != UnorderedSections.size(); ++InsPt) {
UnorderedPos += UnorderedSections[InsPt]->getSize();
@@ -1342,10 +1386,12 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) {
if (A->kind() == InputSectionBase::Synthetic ||
B->kind() == InputSectionBase::Synthetic)
return A->kind() != InputSectionBase::Synthetic;
+
InputSection *LA = A->getLinkOrderDep();
InputSection *LB = B->getLinkOrderDep();
OutputSection *AOut = LA->getParent();
OutputSection *BOut = LB->getParent();
+
if (AOut != BOut)
return AOut->SectionIndex < BOut->SectionIndex;
return LA->OutSecOff < LB->OutSecOff;
@@ -1392,6 +1438,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) {
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
// previous Section.
return true;
@@ -1423,18 +1470,19 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
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.
Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep();
}
+ // The EHABI for the Arm Architecture permits consecutive identical
+ // table entries to be merged. We use a simple implementation that
+ // removes a .ARM.exidx Input Section if it can be merged into the
+ // 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.
if (Config->MergeArmExidx) {
- // The EHABI for the Arm Architecture permits consecutive identical
- // table entries to be merged. We use a simple implementation that
- // removes a .ARM.exidx Input Section if it can be merged into the
- // 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.
size_t Prev = 0;
// The last one is a sentinel entry which should not be removed.
for (size_t I = 1; I < Sections.size() - 1; ++I) {
@@ -1456,11 +1504,49 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
}
}
-static void applySynthetic(const std::vector<SyntheticSection *> &Sections,
- llvm::function_ref<void(SyntheticSection *)> Fn) {
- for (SyntheticSection *SS : Sections)
- if (SS && SS->getParent() && !SS->empty())
- Fn(SS);
+// For most RISC ISAs, we need to generate content that depends on the address
+// of InputSections. For example some architectures such as AArch64 use small
+// displacements 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.
+template <class ELFT> void Writer<ELFT>::maybeAddThunks() {
+ if (!Target->NeedsThunks && !Config->AndroidPackDynRelocs &&
+ !Config->RelrPackDynRelocs)
+ return;
+
+ ThunkCreator TC;
+ AArch64Err843419Patcher A64P;
+
+ for (;;) {
+ bool Changed = false;
+
+ Script->assignAddresses();
+
+ if (Target->NeedsThunks)
+ Changed |= TC.createThunks(OutputSections);
+
+ if (Config->FixCortexA53Errata843419) {
+ if (Changed)
+ Script->assignAddresses();
+ Changed |= A64P.createFixes();
+ }
+
+ if (In.MipsGot)
+ In.MipsGot->updateAllocSize();
+
+ Changed |= In.RelaDyn->updateAllocSize();
+
+ if (In.RelrDyn)
+ Changed |= In.RelrDyn->updateAllocSize();
+
+ if (!Changed)
+ return;
+ }
+}
+
+static void finalizeSynthetic(SyntheticSection *Sec) {
+ if (Sec && !Sec->empty() && Sec->getParent())
+ Sec->finalizeContents();
}
// In order to allow users to manipulate linker-synthesized sections,
@@ -1500,6 +1586,7 @@ static void removeUnusedSyntheticSections() {
// with the same name defined in other ELF executable or DSO.
static bool computeIsPreemptible(const Symbol &B) {
assert(!B.isLocal());
+
// Only symbols that appear in dynsym can be preempted.
if (!B.includeInDynsym())
return false;
@@ -1528,7 +1615,6 @@ static bool computeIsPreemptible(const Symbol &B) {
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
- Out::DebugInfo = findSection(".debug_info");
Out::PreinitArray = findSection(".preinit_array");
Out::InitArray = findSection(".init_array");
Out::FiniArray = findSection(".fini_array");
@@ -1547,46 +1633,51 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// It should be okay as no one seems to care about the type.
// Even the author of gold doesn't remember why gold behaves that way.
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
- if (InX::DynSymTab)
- Symtab->addRegular("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
- /*Size=*/0, STB_WEAK, InX::Dynamic,
+ if (In.Dynamic->Parent)
+ Symtab->addDefined("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/,
+ /*Size=*/0, STB_WEAK, In.Dynamic,
/*File=*/nullptr);
// Define __rel[a]_iplt_{start,end} symbols if needed.
addRelIpltSymbols();
+ // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined.
+ if (Config->EMachine == EM_RISCV)
+ if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$")))
+ addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800);
+
// This responsible for splitting up .eh_frame section into
// pieces. The relocation scan uses those pieces, so this has to be
// earlier.
- applySynthetic({InX::EhFrame},
- [](SyntheticSection *SS) { SS->finalizeContents(); });
+ finalizeSynthetic(In.EhFrame);
for (Symbol *S : Symtab->getSymbols())
- S->IsPreemptible |= computeIsPreemptible(*S);
+ if (!S->IsPreemptible)
+ S->IsPreemptible = computeIsPreemptible(*S);
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
if (!Config->Relocatable)
forEachRelSec(scanRelocations<ELFT>);
- if (InX::Plt && !InX::Plt->empty())
- InX::Plt->addSymbols();
- if (InX::Iplt && !InX::Iplt->empty())
- InX::Iplt->addSymbols();
+ if (In.Plt && !In.Plt->empty())
+ In.Plt->addSymbols();
+ if (In.Iplt && !In.Iplt->empty())
+ In.Iplt->addSymbols();
// Now that we have defined all possible global symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
for (Symbol *Sym : Symtab->getSymbols()) {
if (!includeInSymtab(*Sym))
continue;
- if (InX::SymTab)
- InX::SymTab->addSymbol(Sym);
+ if (In.SymTab)
+ In.SymTab->addSymbol(Sym);
- if (InX::DynSymTab && Sym->includeInDynsym()) {
- InX::DynSymTab->addSymbol(Sym);
+ if (Sym->includeInDynsym()) {
+ In.DynSymTab->addSymbol(Sym);
if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File))
if (File->IsNeeded && !Sym->isUndefined())
- In<ELFT>::VerNeed->addSymbol(Sym);
+ InX<ELFT>::VerNeed->addSymbol(Sym);
}
}
@@ -1594,8 +1685,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
- if (InX::MipsGot)
- InX::MipsGot->build<ELFT>();
+ if (In.MipsGot)
+ In.MipsGot->build<ELFT>();
removeUnusedSyntheticSections();
@@ -1607,15 +1698,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (auto *Sec = dyn_cast<OutputSection>(Base))
OutputSections.push_back(Sec);
- // Ensure data sections are not mixed with executable sections when
- // -execute-only is used.
- if (Config->ExecuteOnly)
- for (OutputSection *OS : OutputSections)
- if (OS->Flags & SHF_EXECINSTR)
- for (InputSection *IS : getInputSections(OS))
- if (!(IS->Flags & SHF_EXECINSTR))
- error("-execute-only does not support intermingling data and code");
-
// Prefer command line supplied address over other constraints.
for (OutputSection *Sec : OutputSections) {
auto I = Config->SectionStartMap.find(Sec->Name);
@@ -1628,10 +1710,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// particularly relevant.
Out::ElfHeader->SectionIndex = 1;
- unsigned I = 1;
- for (OutputSection *Sec : OutputSections) {
- Sec->SectionIndex = I++;
- Sec->ShName = InX::ShStrTab->addString(Sec->Name);
+ for (size_t I = 0, E = OutputSections.size(); I != E; ++I) {
+ OutputSection *Sec = OutputSections[I];
+ Sec->SectionIndex = I + 1;
+ Sec->ShName = In.ShStrTab->addString(Sec->Name);
}
// Binary and relocatable output does not have PHDRS.
@@ -1641,6 +1723,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs();
addPtArmExid(Phdrs);
Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size();
+
+ // Find the TLS segment. This happens before the section layout loop so that
+ // Android relocation packing can look up TLS symbol addresses.
+ for (PhdrEntry *P : Phdrs)
+ if (P->p_type == PT_TLS)
+ Out::TlsPhdr = P;
}
// Some symbols are defined in term of program headers. Now that we
@@ -1649,15 +1737,30 @@ 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::SymTabShndx, 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(); });
+ finalizeSynthetic(In.DynSymTab);
+ finalizeSynthetic(In.Bss);
+ finalizeSynthetic(In.BssRelRo);
+ finalizeSynthetic(In.GnuHashTab);
+ finalizeSynthetic(In.HashTab);
+ finalizeSynthetic(In.SymTabShndx);
+ finalizeSynthetic(In.ShStrTab);
+ finalizeSynthetic(In.StrTab);
+ finalizeSynthetic(In.VerDef);
+ finalizeSynthetic(In.DynStrTab);
+ finalizeSynthetic(In.Got);
+ finalizeSynthetic(In.MipsGot);
+ finalizeSynthetic(In.IgotPlt);
+ finalizeSynthetic(In.GotPlt);
+ finalizeSynthetic(In.RelaDyn);
+ finalizeSynthetic(In.RelrDyn);
+ finalizeSynthetic(In.RelaIplt);
+ finalizeSynthetic(In.RelaPlt);
+ finalizeSynthetic(In.Plt);
+ finalizeSynthetic(In.Iplt);
+ finalizeSynthetic(In.EhFrameHdr);
+ finalizeSynthetic(InX<ELFT>::VerSym);
+ finalizeSynthetic(InX<ELFT>::VerNeed);
+ finalizeSynthetic(In.Dynamic);
if (!Script->HasSectionsCommand && !Config->Relocatable)
fixSectionAlignments();
@@ -1666,37 +1769,21 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// needs to be resolved before any other address dependent operation.
resolveShfLinkOrder();
- // 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 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 ||
- Config->RelrPackDynRelocs) {
- ThunkCreator TC;
- AArch64Err843419Patcher A64P;
- bool Changed;
- do {
- Script->assignAddresses();
- Changed = false;
- if (Target->NeedsThunks)
- Changed |= TC.createThunks(OutputSections);
- if (Config->FixCortexA53Errata843419) {
- if (Changed)
- Script->assignAddresses();
- Changed |= A64P.createFixes();
- }
- if (InX::MipsGot)
- InX::MipsGot->updateAllocSize();
- Changed |= InX::RelaDyn->updateAllocSize();
- if (InX::RelrDyn)
- Changed |= InX::RelrDyn->updateAllocSize();
- } while (Changed);
- }
+ // Jump instructions in many ISAs have small displacements, and therefore they
+ // cannot jump to arbitrary addresses in memory. For example, RISC-V JAL
+ // instruction can target only +-1 MiB from PC. It is a linker's
+ // responsibility to create and insert small pieces of code between sections
+ // to extend the ranges if jump targets are out of range. Such code pieces are
+ // called "thunks".
+ //
+ // We add thunks at this stage. We couldn't do this before this point because
+ // this is the earliest point where we know sizes of sections and their
+ // layouts (that are needed to determine if jump targets are in range).
+ maybeAddThunks();
- // createThunks may have added local symbols to the static symbol table
- applySynthetic({InX::SymTab},
- [](SyntheticSection *SS) { SS->postThunkContents(); });
+ // maybeAddThunks may have added local symbols to the static symbol table.
+ finalizeSynthetic(In.SymTab);
+ finalizeSynthetic(In.PPC64LongBranchTarget);
// Fill other section headers. The dynamic table is finalized
// at the end because some tags like RELSZ depend on result
@@ -1705,6 +1792,21 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
Sec->finalize<ELFT>();
}
+// Ensure data sections are not mixed with executable sections when
+// -execute-only is used. -execute-only is a feature to make pages executable
+// but not readable, and the feature is currently supported only on AArch64.
+template <class ELFT> void Writer<ELFT>::checkExecuteOnly() {
+ if (!Config->ExecuteOnly)
+ return;
+
+ for (OutputSection *OS : OutputSections)
+ if (OS->Flags & SHF_EXECINSTR)
+ for (InputSection *IS : getInputSections(OS))
+ if (!(IS->Flags & SHF_EXECINSTR))
+ error("cannot place " + toString(IS) + " into " + toString(OS->Name) +
+ ": -execute-only does not support intermingling data and code");
+}
+
// 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() {
@@ -1721,9 +1823,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
// 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.
+ //
+ // In a rare sitaution, .text section may not exist. If that's the
+ // case, use the image base address as a last resort.
OutputSection *Default = findSection(".text");
if (!Default)
Default = Out::ElfHeader;
+
auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) {
if (OS) {
addOptionalRegular(Start, OS, 0);
@@ -1763,7 +1869,7 @@ static bool needsPtLoad(OutputSection *Sec) {
// Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is
// responsible for allocating space for them, not the PT_LOAD that
// contains the TLS initialization image.
- if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS)
+ if ((Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS)
return false;
return true;
}
@@ -1815,12 +1921,14 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
// Segments are contiguous memory regions that has the same attributes
// (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. 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.
+ // different flags or is loaded at a discontiguous address or memory
+ // region using AT or AT> linker script command, respectively. 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 or AT> attribute.
uint64_t NewFlags = computeFlags(Sec->getPhdrFlags());
- if ((Sec->LMAExpr && Load->LastSec != Out::ProgramHeaders) ||
+ if (((Sec->LMAExpr ||
+ (Sec->LMARegion && (Sec->LMARegion != Load->FirstSec->LMARegion))) &&
+ Load->LastSec != Out::ProgramHeaders) ||
Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) {
Load = AddHdr(PT_LOAD, NewFlags);
@@ -1839,9 +1947,8 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
Ret.push_back(TlsHdr);
// Add an entry for .dynamic.
- if (InX::DynSymTab)
- AddHdr(PT_DYNAMIC, InX::Dynamic->getParent()->getPhdrFlags())
- ->add(InX::Dynamic->getParent());
+ if (OutputSection *Sec = In.Dynamic->getParent())
+ AddHdr(PT_DYNAMIC, Sec->getPhdrFlags())->add(Sec);
// PT_GNU_RELRO includes all sections that should be marked as
// read-only by dynamic linker after proccessing relocations.
@@ -1869,10 +1976,10 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() {
Ret.push_back(RelRo);
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
- if (!InX::EhFrame->empty() && InX::EhFrameHdr && InX::EhFrame->getParent() &&
- InX::EhFrameHdr->getParent())
- AddHdr(PT_GNU_EH_FRAME, InX::EhFrameHdr->getParent()->getPhdrFlags())
- ->add(InX::EhFrameHdr->getParent());
+ if (!In.EhFrame->empty() && In.EhFrameHdr && In.EhFrame->getParent() &&
+ In.EhFrameHdr->getParent())
+ AddHdr(PT_GNU_EH_FRAME, In.EhFrameHdr->getParent()->getPhdrFlags())
+ ->add(In.EhFrameHdr->getParent());
// PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes
// the dynamic linker fill the segment with random data.
@@ -1943,77 +2050,77 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
for (const PhdrEntry *P : Phdrs) {
if (P->p_type != PT_GNU_RELRO)
continue;
+
if (P->FirstSec)
PageAlign(P->FirstSec);
+
// Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we
// have to align it to a page.
auto End = OutputSections.end();
auto I = std::find(OutputSections.begin(), End, P->LastSec);
if (I == End || (I + 1) == End)
continue;
+
OutputSection *Cmd = (*(I + 1));
if (needsPtLoad(Cmd))
PageAlign(Cmd);
}
}
-// Adjusts the file alignment for a given output section and returns
-// its new file offset. The file offset must be the same with its
-// virtual address (modulo the page size) so that the loader can load
-// executables without any address adjustment.
-static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) {
- 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)
+// Compute an in-file position for a given section. The file offset must be the
+// same with its virtual address modulo the page size, so that the loader can
+// load executables without any address adjustment.
+static uint64_t computeFileOffset(OutputSection *OS, uint64_t Off) {
+ // File offsets are not significant for .bss sections. By convention, we keep
+ // section offsets monotonically increasing rather than setting to zero.
+ if (OS->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 (!OS->PtLoad)
+ return alignTo(Off, OS->Alignment);
+
+ // The first section in a PT_LOAD has to have congruent offset and address
+ // module the page size.
+ OutputSection *First = OS->PtLoad->FirstSec;
+ if (OS == First) {
+ uint64_t Alignment = std::max<uint64_t>(OS->Alignment, Config->MaxPageSize);
+ return alignTo(Off, Alignment, OS->Addr);
+ }
// 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;
+ return First->Offset + OS->Addr - First->Addr;
}
-static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) {
- Off = getFileAlignment(Off, Cmd);
- Cmd->Offset = Off;
+// Set an in-file position to a given section and returns the end position of
+// the section.
+static uint64_t setFileOffset(OutputSection *OS, uint64_t Off) {
+ Off = computeFileOffset(OS, Off);
+ OS->Offset = Off;
- // For SHT_NOBITS we should not count the size.
- if (Cmd->Type == SHT_NOBITS)
+ if (OS->Type == SHT_NOBITS)
return Off;
-
- return Off + Cmd->Size;
+ return Off + OS->Size;
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
uint64_t Off = 0;
for (OutputSection *Sec : OutputSections)
if (Sec->Flags & SHF_ALLOC)
- Off = setOffset(Sec, Off);
+ Off = setFileOffset(Sec, Off);
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;
- Off = setOffset(Out::ElfHeader, Off);
- Off = setOffset(Out::ProgramHeaders, Off);
+ Off = setFileOffset(Out::ElfHeader, Off);
+ Off = setFileOffset(Out::ProgramHeaders, Off);
PhdrEntry *LastRX = nullptr;
for (PhdrEntry *P : Phdrs)
@@ -2021,9 +2128,10 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
LastRX = P;
for (OutputSection *Sec : OutputSections) {
- Off = setOffset(Sec, Off);
+ Off = setFileOffset(Sec, Off);
if (Script->HasSectionsCommand)
continue;
+
// If this is a last section of the last executable segment and that
// segment is the last loadable segment, align the offset of the
// following section to avoid loading non-segments parts of the file.
@@ -2048,7 +2156,7 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
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) +
+ rangeToString(Sec->Offset, Sec->Size) +
"; check your linker script for overflows");
}
}
@@ -2059,19 +2167,23 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
for (PhdrEntry *P : Phdrs) {
OutputSection *First = P->FirstSec;
OutputSection *Last = P->LastSec;
+
if (First) {
P->p_filesz = Last->Offset - First->Offset;
if (Last->Type != SHT_NOBITS)
P->p_filesz += Last->Size;
+
P->p_memsz = Last->Addr + Last->Size - First->Addr;
P->p_offset = First->Offset;
P->p_vaddr = First->Addr;
+
if (!P->HasLMA)
P->p_paddr = First->getLMA();
}
- if (P->p_type == PT_LOAD)
+
+ if (P->p_type == PT_LOAD) {
P->p_align = std::max<uint64_t>(P->p_align, Config->MaxPageSize);
- else if (P->p_type == PT_GNU_RELRO) {
+ } else if (P->p_type == PT_GNU_RELRO) {
P->p_align = 1;
// The glibc dynamic loader rounds the size down, so we need to round up
// to protect the last page. This is a no-op on FreeBSD which always
@@ -2079,12 +2191,22 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() {
P->p_memsz = alignTo(P->p_memsz, Target->PageSize);
}
- // The TLS pointer goes after PT_TLS. At least glibc will align it,
- // so round up the size to make sure the offsets are correct.
- if (P->p_type == PT_TLS) {
- Out::TlsPhdr = P;
- if (P->p_memsz)
- P->p_memsz = alignTo(P->p_memsz, P->p_align);
+ if (P->p_type == PT_TLS && P->p_memsz) {
+ if (!Config->Shared &&
+ (Config->EMachine == EM_ARM || Config->EMachine == EM_AARCH64)) {
+ // On ARM/AArch64, reserve extra space (8 words) between the thread
+ // pointer and an executable's TLS segment by overaligning the segment.
+ // This reservation is needed for backwards compatibility with Android's
+ // TCB, which allocates several slots after the thread pointer (e.g.
+ // TLS_SLOT_STACK_GUARD==5). For simplicity, this overalignment is also
+ // done on other operating systems.
+ P->p_align = std::max<uint64_t>(P->p_align, Config->Wordsize * 8);
+ }
+
+ // The TLS pointer goes after PT_TLS for variant 2 targets. At least glibc
+ // will align it, so round up the size to make sure the offsets are
+ // correct.
+ P->p_memsz = alignTo(P->p_memsz, P->p_align);
}
}
}
@@ -2101,10 +2223,9 @@ struct SectionOffset {
// 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;
- });
+ llvm::sort(Sections, [=](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.
@@ -2148,7 +2269,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// 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 &&
+ if (Sec->Size > 0 && Sec->Type != SHT_NOBITS &&
(!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC)))
FileOffs.push_back({Sec, Sec->Offset});
checkOverlap("file", FileOffs, false);
@@ -2166,7 +2287,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// ranges in the file.
std::vector<SectionOffset> VMAs;
for (OutputSection *Sec : OutputSections)
- if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
VMAs.push_back({Sec, Sec->Addr});
checkOverlap("virtual address", VMAs, true);
@@ -2175,7 +2296,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// script with AT().
std::vector<SectionOffset> LMAs;
for (OutputSection *Sec : OutputSections)
- if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
+ if (Sec->Size > 0 && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS))
LMAs.push_back({Sec, Sec->getLMA()});
checkOverlap("load address", LMAs, false);
}
@@ -2188,7 +2309,7 @@ template <class ELFT> void Writer<ELFT>::checkSections() {
// 4. the number represented by the entry symbol, if it is a number;
// 5. the address of the first byte of the .text section, if present;
// 6. the address 0.
-template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {
+static uint64_t getEntryAddr() {
// Case 1, 2 or 3
if (Symbol *B = Symtab->find(Config->Entry))
return B->getVA();
@@ -2231,6 +2352,7 @@ static uint8_t getAbiVersion() {
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.
@@ -2289,7 +2411,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
else
EHdr->e_shnum = Num;
- uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex;
+ uint32_t StrTabIndex = In.ShStrTab->getParent()->SectionIndex;
if (StrTabIndex >= SHN_LORESERVE) {
SHdrs->sh_link = StrTabIndex;
EHdr->e_shstrndx = SHN_XINDEX;
@@ -2303,7 +2425,8 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
// Open a result file.
template <class ELFT> void Writer<ELFT>::openFile() {
- if (!Config->Is64 && FileSize > UINT32_MAX) {
+ uint64_t MaxSize = Config->Is64 ? INT64_MAX : UINT32_MAX;
+ if (MaxSize < FileSize) {
error("output file too large: " + Twine(FileSize) + " bytes");
return;
}
@@ -2368,8 +2491,8 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
uint8_t *Buf = Buffer->getBufferStart();
OutputSection *EhFrameHdr = nullptr;
- if (InX::EhFrameHdr && !InX::EhFrameHdr->empty())
- EhFrameHdr = InX::EhFrameHdr->getParent();
+ if (In.EhFrameHdr && !In.EhFrameHdr->empty())
+ EhFrameHdr = In.EhFrameHdr->getParent();
// In -r or -emit-relocs mode, write the relocation sections first as in
// ELf_Rel targets we might find out that we need to modify the relocated
@@ -2389,13 +2512,13 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
}
template <class ELFT> void Writer<ELFT>::writeBuildId() {
- if (!InX::BuildId || !InX::BuildId->getParent())
+ if (!In.BuildId || !In.BuildId->getParent())
return;
// Compute a hash of all sections of the output file.
uint8_t *Start = Buffer->getBufferStart();
uint8_t *End = Start + FileSize;
- InX::BuildId->writeBuildId({Start, End});
+ In.BuildId->writeBuildId({Start, End});
}
template void elf::writeResult<ELF32LE>();
diff --git a/LICENSE.TXT b/LICENSE.TXT
index e05e1845766e..09b8b616c227 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -4,7 +4,7 @@ lld License
University of Illinois/NCSA
Open Source License
-Copyright (c) 2011-2018 by the contributors listed in CREDITS.TXT
+Copyright (c) 2011-2019 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
diff --git a/MinGW/Driver.cpp b/MinGW/Driver.cpp
index 27a5550ec9c7..def769bb9125 100644
--- a/MinGW/Driver.cpp
+++ b/MinGW/Driver.cpp
@@ -6,9 +6,27 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
-///
-/// GNU ld style linker driver for COFF currently supporting mingw-w64.
-///
+//
+// MinGW is a GNU development environment for Windows. It consists of GNU
+// tools such as GCC and GNU ld. Unlike Cygwin, there's no POSIX-compatible
+// layer, as it aims to be a native development toolchain.
+//
+// lld/MinGW is a drop-in replacement for GNU ld/MinGW.
+//
+// Being a native development tool, a MinGW linker is not very different from
+// Microsoft link.exe, so a MinGW linker can be implemented as a thin wrapper
+// for lld/COFF. This driver takes Unix-ish command line options, translates
+// them to Windows-ish ones, and then passes them to lld/COFF.
+//
+// When this driver calls the lld/COFF driver, it passes a hidden option
+// "-lldmingw" along with other user-supplied options, to run the lld/COFF
+// linker in "MinGW mode".
+//
+// There are subtle differences between MS link.exe and GNU ld/MinGW, and GNU
+// ld/MinGW implements a few GNU-specific features. Such features are directly
+// implemented in lld/COFF and enabled only when the linker is running in MinGW
+// mode.
+//
//===----------------------------------------------------------------------===//
#include "lld/Common/Driver.h"
@@ -212,9 +230,14 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) {
else
Add("-alternatename:__image_base__=__ImageBase");
+ for (auto *A : Args.filtered(OPT_require_defined))
+ Add("-include:" + StringRef(A->getValue()));
+
std::vector<StringRef> SearchPaths;
- for (auto *A : Args.filtered(OPT_L))
+ for (auto *A : Args.filtered(OPT_L)) {
SearchPaths.push_back(A->getValue());
+ Add("-libpath:" + StringRef(A->getValue()));
+ }
StringRef Prefix = "";
bool Static = false;
diff --git a/MinGW/Options.td b/MinGW/Options.td
index ad699f71134a..948faa687521 100644
--- a/MinGW/Options.td
+++ b/MinGW/Options.td
@@ -40,6 +40,9 @@ def strip_debug: F<"strip-debug">,
def whole_archive: F<"whole-archive">,
HelpText<"Include all object files for following archives">;
def verbose: F<"verbose">, HelpText<"Verbose mode">;
+def require_defined: S<"require-defined">,
+ HelpText<"Force symbol to be added to symbol table as an undefined one">;
+def require_defined_eq: J<"require-defined=">, Alias<require_defined>;
// LLD specific options
def _HASH_HASH_HASH : Flag<["-"], "###">,
diff --git a/docs/NewLLD.rst b/docs/NewLLD.rst
index afdb41e0a145..79bdf90c6ccd 100644
--- a/docs/NewLLD.rst
+++ b/docs/NewLLD.rst
@@ -53,7 +53,7 @@ between speed, simplicity and extensibility.
until we need them to continue linking.
When we need to do some costly operation (such as looking up
a hash table for each symbol), we do it only once.
- We obtain a handler (which is typically just a pointer to actual data)
+ We obtain a handle (which is typically just a pointer to actual data)
on the first operation and use it throughout the process.
* Efficient archive file handling
@@ -90,18 +90,18 @@ between speed, simplicity and extensibility.
`--end-group`, to let the linker loop over the files between the options until
no new symbols are added to the set.
- Visiting the same archive files multiple makes the linker slower.
+ Visiting the same archive files multiple times makes the linker slower.
Here is how LLD approaches the problem. Instead of memorizing only undefined
symbols, we program LLD so that it memorizes all symbols. When it sees an
undefined symbol that can be resolved by extracting an object file from an
- archive file it previously visited, it immediately extracts the file and link
- it. It is doable because LLD does not forget symbols it have seen in archive
+ archive file it previously visited, it immediately extracts the file and links
+ it. It is doable because LLD does not forget symbols it has seen in archive
files.
- We believe that the LLD's way is efficient and easy to justify.
+ We believe that LLD's way is efficient and easy to justify.
- The semantics of LLD's archive handling is different from the traditional
+ The semantics of LLD's archive handling are different from the traditional
Unix's. You can observe it if you carefully craft archive files to exploit
it. However, in reality, we don't know any program that cannot link with our
algorithm so far, so it's not going to cause trouble.
@@ -157,7 +157,7 @@ functions, the code of the linker should look obvious to you.
- Undefined symbols represent undefined symbols, which need to be replaced by
Defined symbols by the resolver until the link is complete.
- Lazy symbols represent symbols we found in archive file headers
- which can turn into Defined if we read archieve members.
+ which can turn into Defined if we read archive members.
There's only one Symbol instance for each unique symbol name. This uniqueness
is guaranteed by the symbol table. As the resolver reads symbols from input
diff --git a/docs/README.txt b/docs/README.txt
index eb09a2d2b7ea..2ed016639de7 100644
--- a/docs/README.txt
+++ b/docs/README.txt
@@ -6,7 +6,4 @@ currently tested with Sphinx 1.1.3.
We currently use the 'nature' theme and a Beaker inspired structure.
-To rebuild documents into html:
-
- [/lld/docs]> make html
-
+See sphinx_intro.rst for more details.
diff --git a/docs/Readers.rst b/docs/Readers.rst
index b69a0b34fabe..eae1717f6e5b 100644
--- a/docs/Readers.rst
+++ b/docs/Readers.rst
@@ -74,7 +74,7 @@ files in parallel. Therefore, there should be no parsing state in you Reader
object. Any parsing state should be in ivars of your File subclass or in
some temporary object.
-The key method to implement in a reader is::
+The key function to implement in a reader is::
virtual error_code loadFile(LinkerInput &input,
std::vector<std::unique_ptr<File>> &result);
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index 7ac1f9ce565b..dc5df6795d99 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -1,22 +1,22 @@
=======================
-LLD 7.0.0 Release Notes
+lld 8.0.0 Release Notes
=======================
.. contents::
:local:
.. warning::
- These are in-progress notes for the upcoming LLVM 7.0.0 release.
+ These are in-progress notes for the upcoming LLVM 8.0.0 release.
Release notes for previous releases can be found on
- `the Download Page <http://releases.llvm.org/download.html>`_.
+ `the Download Page <https://releases.llvm.org/download.html>`_.
Introduction
============
-This document contains the release notes for the lld linker, release 7.0.0.
+This document contains the release notes for the lld linker, release 8.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/>`_.
+from the `LLVM releases web site <https://llvm.org/releases/>`_.
Non-comprehensive list of changes in this release
=================================================
@@ -24,14 +24,57 @@ Non-comprehensive list of changes in this release
ELF Improvements
----------------
-* Item 1.
+* lld now supports RISC-V. (`r339364
+ <https://reviews.llvm.org/rL339364>`_)
+
+* Default image base address has changed from 65536 to 2 MiB for i386
+ and 4 MiB for AArch64 to make lld-generated executables work better
+ with automatic superpage promotion. FreeBSD can promote contiguous
+ non-superpages to a superpage if they are aligned to the superpage
+ size. (`r342746 <https://reviews.llvm.org/rL342746>`_)
+
+* lld/Hexagon can now link Linux kernel and musl libc for Qualcomm
+ Hexagon ISA.
+
+* Initial MSP430 ISA support has landed.
+
+* The following flags have been added: ``-z interpose``, ``-z global``
COFF Improvements
-----------------
-* Item 1.
+* PDB GUID is set to hash of PDB contents instead to a random byte
+ sequence for build reproducibility.
+
+* The following flags have been added: ``/force:multiple``
+
+* lld now can link against import libraries produced by GNU tools.
+
+* lld can create thunks for ARM, to allow linking images over 16 MB.
+
+MinGW Improvements
+------------------
+
+* lld can now automatically import data variables from DLLs without the
+ use of the dllimport attribute.
+
+* lld can now use existing normal MinGW sysroots with import libraries and
+ CRT startup object files for GNU binutils. lld can handle most object
+ files produced by GCC, and thus works as a drop-in replacement for
+ ld.bfd in such environments. (There are known issues with linking crtend.o
+ from GCC in setups with DWARF exceptions though, where object files are
+ linked in a different order than with GNU ld, inserting a DWARF exception
+ table terminator too early.)
MachO Improvements
------------------
* Item 1.
+
+WebAssembly Improvements
+------------------------
+
+* Add initial support for creating shared libraries (-shared).
+ Note: The shared library format is still under active development and may
+ undergo significant changes in future versions.
+ See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
diff --git a/docs/WebAssembly.rst b/docs/WebAssembly.rst
index 264d221970b1..424c1a10c7e7 100644
--- a/docs/WebAssembly.rst
+++ b/docs/WebAssembly.rst
@@ -1,13 +1,10 @@
WebAssembly lld port
====================
-Note: The WebAssembly port is still a work in progress and is be lacking
-certain features.
-
The WebAssembly version of lld takes WebAssembly binaries as inputs and produces
-a WebAssembly binary as its output. For the most part this port tried to mimic
-the behaviour of traditional ELF linkers and specifically the ELF lld port.
-Where possible that command line flags and the semantics should be the same.
+a WebAssembly binary as its output. For the most part it tries to mimic the
+behaviour of traditional ELF linkers and specifically the ELF lld port. Where
+possible that command line flags and the semantics should be the same.
Object file format
@@ -23,14 +20,95 @@ currently requires enabling the experimental backed using
``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
+Usage
+-----
+
+The WebAssembly version of lld is installed as **wasm-ld**. It shared many
+common linker flags with **ld.lld** but also includes several
+WebAssembly-specific options:
+
+.. option:: --no-entry
+
+ Don't search for the entry point symbol (by default ``_start``).
+
+.. option:: --export-table
+
+ Export the function table to the environment.
+
+.. option:: --import-table
+
+ Import the function table from the environment.
+
+.. option:: --export-all
+
+ Export all symbols (normally combined with --no-gc-sections)
+
+.. option:: --export-dynamic
+
+ When building an executable, export any non-hidden symbols. By default only
+ the entry point and any symbols marked with --export/--export-all are
+ exported.
+
+.. option:: --global-base=<value>
+
+ Address at which to place global data.
+
+.. option:: --no-merge-data-segments
+
+ Disable merging of data segments.
+
+.. option:: --stack-first
+
+ Place stack at start of linear memory rather than after data.
+
+.. option:: --compress-relocations
+
+ Relocation targets in the code section 5-bytes wide in order to potentially
+ occomate the largest LEB128 value. This option will cause the linker to
+ shirnk the code section to remove any padding from the final output. However
+ because it effects code offset, this option is not comatible with outputing
+ debug information.
+
+.. option:: --allow-undefined
+
+ Allow undefined symbols in linked binary.
+
+.. option:: --import-memory
+
+ Import memory from the environment.
+
+.. option:: --initial-memory=<value>
+
+ Initial size of the linear memory. Default: static data size.
+
+.. option:: --max-memory=<value>
+
+ Maximum size of the linear memory. Default: unlimited.
+
+By default the function table is neither imported nor exported, but defined
+for internal use only.
+
+When building shared libraries symbols are exported if they are marked
+as ``visibility=default``. When building executables only the entry point is
+exported by default. In addition any symbol included on the command line via
+``--export`` is also exported.
+
+Since WebAssembly is designed with size in mind the linker defaults to
+``--gc-sections`` which means that all unused functions and data segments will
+be stripped from the binary.
+
+The symbols which are preserved by default are:
+
+- The entry point (by default ``_start``).
+- Any symbol which is to be exported.
+- Any symbol transitively referenced by the above.
+
+
Missing features
----------------
-There are several key features that are not yet implement in the WebAssembly
-ports:
-
-- COMDAT support. This means that support for C++ is still very limited.
-- Function stripping. Currently there is no support for ``--gc-sections`` so
- functions and data from a given object will linked as a unit.
-- Section start/end symbols. The synthetic symbols that mark the start and
- of data regions are not yet created in the output file.
+- Merging of data section similar to ``SHF_MERGE`` in the ELF world is not
+ supported.
+- No support for creating shared libraries. The spec for shared libraries in
+ WebAssembly is still in flux:
+ https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
diff --git a/docs/conf.py b/docs/conf.py
index 3598fbf50f0d..62404b275450 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 = '7'
+version = '8'
# The full version, including alpha/beta/rc tags.
-release = '7'
+release = '8'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index 2821ce4d214e..da1c894f3d83 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,7 +1,7 @@
LLD - The LLVM Linker
=====================
-LLD is a linker from the LLVM project. That is a drop-in replacement
+LLD is a linker from the LLVM project that is a drop-in replacement
for system linkers and runs much faster than them. It also provides
features that are useful for toolchain developers.
@@ -17,7 +17,7 @@ read :doc:`AtomLLD`.
Features
--------
-- LLD is a drop-in replacement for the GNU linkers. That accepts the
+- LLD is a drop-in replacement for the GNU linkers that accepts the
same command line arguments and linker scripts as GNU.
We are currently working closely with the FreeBSD project to make
@@ -30,29 +30,27 @@ Features
<https://www.freebsd.org/news/status/report-2016-10-2016-12.html#Using-LLVM%27s-LLD-Linker-as-FreeBSD%27s-System-Linker>`_.
- LLD is very fast. When you link a large program on a multicore
- machine, you can expect that LLD runs more than twice as fast as GNU
+ machine, you can expect that LLD runs more than twice as fast as the GNU
gold linker. Your milage may vary, though.
- It supports various CPUs/ABIs including x86-64, x86, x32, AArch64,
ARM, MIPS 32/64 big/little-endian, PowerPC, PowerPC 64 and AMDGPU.
- Among these, x86-64 is the most well-supported target and have
- reached production quality. AArch64 and MIPS seem decent too. x86
- should be OK but not well tested yet. ARM support is being developed
- actively.
+ Among these, x86-64, AArch64, and ARM (>= v6) are production quality.
+ MIPS seems decent too. x86 should be OK but is not well tested yet.
- It is always a cross-linker, meaning that it always supports all the
above targets however it was built. In fact, we don't provide a
build-time option to enable/disable each target. This should make it
easy to use our linker as part of a cross-compile toolchain.
-- You can embed LLD to your program to eliminate dependency to
+- You can embed LLD in your program to eliminate dependencies on
external linkers. All you have to do is to construct object files
and command line arguments just like you would do to invoke an
external linker and then call the linker's main function,
``lld::elf::link``, from your code.
- It is small. We are using LLVM libObject library to read from object
- files, so it is not completely a fair comparison, but as of February
+ files, so it is not a completely fair comparison, but as of February
2017, LLD/ELF consists only of 21k lines of C++ code while GNU gold
consists of 198k lines of C++ code.
@@ -102,8 +100,8 @@ under ``tools`` directory just like you probably did for clang. For the
details, see `Getting Started with the LLVM System
<http://llvm.org/docs/GettingStarted.html>`_.
-If you haven't checkout out LLVM, the easiest way to build LLD is to
-checkout the entire LLVM projects/sub-projects from a git mirror and
+If you haven't checked out LLVM, the easiest way to build LLD is to
+check out the entire LLVM projects/sub-projects from a git mirror and
build that tree. You need `cmake` and of course a C++ compiler.
.. code-block:: console
diff --git a/docs/ld.lld.1 b/docs/ld.lld.1
index 0fdfe0ae7e89..d1ce4a3517f4 100644
--- a/docs/ld.lld.1
+++ b/docs/ld.lld.1
@@ -3,7 +3,7 @@
.\"
.\" This man page documents only lld's ELF linking support, obtained originally
.\" from FreeBSD.
-.Dd July 30, 2018
+.Dd September 26, 2018
.Dt LD.LLD 1
.Os
.Sh NAME
@@ -13,6 +13,7 @@
.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
@@ -25,7 +26,21 @@ 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:
+.Nm
+currently supports i386, x86-64, ARM, AArch64, PowerPC32, PowerPC64,
+MIPS32, MIPS64, RISC-V, AMDGPU, Hexagon and SPARC V9 targets.
+.Nm
+acts as a Microsoft link.exe-compatible linker if invoked as
+.Nm lld-link
+and as macOS's ld if invoked as
+.Nm ld.ld64.
+All these targets are always supported however
+.Nm
+was built, so you can always use
+.Nm
+as a native linker as well as a cross linker.
+
+.Sh OPTIONS
.Bl -tag -width indent
.It Fl -allow-multiple-definition
Do not error if a symbol is defined multiple times.
@@ -144,6 +159,9 @@ 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 -execute-only
+Mark executable sections unreadable. This option is currently only
+supported on AArch64.
.It Fl -exclude-libs Ns = Ns Ar value
Exclude static libraries from automatic export.
.It Fl -export-dynamic , Fl E
@@ -297,6 +315,8 @@ Include hotness information in the optimization remarks file.
Create a position independent executable.
.It Fl -print-gc-sections
List removed unused sections.
+.It Fl -print-icf-sections
+List identical folded sections.
.It Fl -print-map
Print a link map to the standard output.
.It Fl -push-state
@@ -304,7 +324,7 @@ Save the current state of
.Fl -as-needed ,
.Fl -static ,
and
-.Fl -while-archive.
+.Fl -whole-archive.
.It Fl -pop-state
Undo the effect of
.Fl -push-state.
@@ -426,6 +446,17 @@ 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-ifunc-textrel
+Warn about using ifunc symbols in conjunction with text relocations.
+Older versions of glibc library (2.28 and earlier) has a bug that causes
+the segment that includes ifunc symbols to be marked as not executable when
+they are relocated. As a result, although the program compiles and links
+successfully, it gives segmentation fault when the instruction pointer reaches
+an ifunc symbol. Use -warn-ifunc-textrel to let lld give a warning, if the
+code may include ifunc symbols, may do text relocations and be linked with
+an older glibc version. Otherwise, there is no need to use it, as the default
+value does not give a warning. This flag has been introduced in late 2018,
+has no counter part in ld and gold linkers, and may be removed in the future.
.It Fl -warn-unresolved-symbols
Report unresolved symbols as warnings.
.It Fl -whole-archive
@@ -440,10 +471,22 @@ Make the main stack executable.
Stack permissions are recorded in the
.Dv PT_GNU_STACK
segment.
+.It Cm global
+Sets the
+.Dv DF_1_GLOBAL flag in the
+.Dv DYNAMIC
+section.
+Different loaders can decide how to handle this flag on their own.
.It Cm initfirst
Sets the
.Dv DF_1_INITFIRST
flag to indicate the module should be initialized first.
+.It Cm interpose
+Set the
+.Dv DF_1_INTERPOSE
+flag to indicate to the runtime linker that the object is an interposer.
+During symbol resolution interposers are searched after the application
+but before other dependencies.
.It Cm muldefs
Do not error if a symbol is defined multiple times.
The first definition will be used.
@@ -453,6 +496,10 @@ This is a synonym for
Disable combining and sorting multiple relocation sections.
.It Cm nocopyreloc
Disable the creation of copy relocations.
+.It Cm nodefaultlib
+Set the
+.Dv DF_1_NODEFLIB
+flag to indicate that default library search paths should be ignored.
.It Cm nodelete
Set the
.Dv DF_1_NODELETE
@@ -460,7 +507,7 @@ 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
+flag to indicate 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
diff --git a/docs/missingkeyfunction.rst b/docs/missingkeyfunction.rst
new file mode 100644
index 000000000000..410c749c3b03
--- /dev/null
+++ b/docs/missingkeyfunction.rst
@@ -0,0 +1,84 @@
+Missing Key Method
+==================
+
+If your build failed with a linker error something like this::
+
+ foo.cc:28: error: undefined reference to 'vtable for C'
+ the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeyfunction)
+
+it's likely that your class C has a key function (defined by the ABI as the first
+non-pure, non-inline, virtual method), but you haven't actually defined it.
+
+When a class has a key function, the compiler emits the vtable (and some other
+things as well) only in the translation unit that defines that key function. Thus,
+if you're missing the key function, you'll also be missing the vtable. If no other
+function calls your missing method, you won't see any undefined reference errors
+for it, but you will see undefined references to the vtable symbol.
+
+When a class has no non-pure, non-inline, virtual methods, there is no key
+method, and the compiler is forced to emit the vtable in every translation unit
+that references the class. In this case, it is emitted in a COMDAT section,
+which allows the linker to eliminate all duplicate copies. This is still
+wasteful in terms of object file size and link time, so it's always advisable to
+ensure there is at least one eligible method that can serve as the key function.
+
+Here are the most common mistakes that lead to this error:
+
+Failing to define a virtual destructor
+--------------------------------------
+
+Say you have a base class declared in a header file::
+
+ class B {
+ public:
+ B();
+ virtual ~B();
+ ...
+ };
+
+Here, ``~B`` is the first non-pure, non-inline, virtual method, so it is the key
+method. If you forget to define ``B::~B`` in your source file, the compiler will
+not emit the vtable for ``B``, and you'll get an undefined reference to "vtable
+for B".
+
+This is just an example of the more general mistake of forgetting to define the
+key function, but it's quite common because virtual destructors are likely to be
+the first eligible key function and it's easy to forget to implement them. It's
+also more likely that you won't have any direct references to the destructor, so
+you won't see any undefined reference errors that point directly to the problem.
+
+The solution in this case is to implement the missing method.
+
+Forgetting to declare a virtual method in an abstract class as pure
+-------------------------------------------------------------------
+
+Say you have an abstract base class declared in a header file::
+
+ class A {
+ public:
+ A();
+ virtual ~A() {}
+ virtual int foo() = 0;
+ ...
+ virtual int bar();
+ ...
+ };
+
+This base class is intended to be abstract, but you forgot to mark one of the
+methods pure. Here, ``A::bar``, being non-pure, is nominated as the key function,
+and as a result, the vtable for ``A`` is not emitted, because the compiler is
+waiting for a translation unit that defines ``A::bar``.
+
+The solution in this case is to add the missing ``= 0`` to the declaration of
+``A::bar``.
+
+Key method is defined, but the linker doesn't see it
+----------------------------------------------------
+
+It's also possible that you have defined the key function somewhere, but the
+object file containing the definition of that method isn't being linked into
+your application.
+
+The solution in this case is to check your dependencies to make sure that
+the object file or the library file containing the key function is given to
+the linker.
diff --git a/docs/open_projects.rst b/docs/open_projects.rst
index eeb9f9f48f34..36edca4e96dc 100644
--- a/docs/open_projects.rst
+++ b/docs/open_projects.rst
@@ -3,8 +3,6 @@
Open Projects
=============
-.. include:: ../include/lld/Core/TODO.txt
-
Documentation TODOs
~~~~~~~~~~~~~~~~~~~
diff --git a/docs/windows_support.rst b/docs/windows_support.rst
index a0a2c4d9f1bc..c9723c42fcc8 100644
--- a/docs/windows_support.rst
+++ b/docs/windows_support.rst
@@ -20,8 +20,8 @@ command line options, and it drives further linking processes. LLD accepts
almost all command line options that the linker shipped with Microsoft Visual
C++ (link.exe) supports.
-The current status is that LLD can link itself on Windows x86/x64
-using Visual C++ 2013 as the compiler.
+The current status is that LLD is used to link production builds of large
+real-world binaries such as Firefox and Chromium.
Development status
==================
diff --git a/include/lld/Common/Args.h b/include/lld/Common/Args.h
index c49a6a7e17e7..769d4840cf06 100644
--- a/include/lld/Common/Args.h
+++ b/include/lld/Common/Args.h
@@ -29,6 +29,9 @@ uint64_t getZOptionValue(llvm::opt::InputArgList &Args, int Id, StringRef Key,
uint64_t Default);
std::vector<StringRef> getLines(MemoryBufferRef MB);
+
+StringRef getFilenameWithoutExe(StringRef Path);
+
} // namespace args
} // namespace lld
diff --git a/include/lld/Common/ErrorHandler.h b/include/lld/Common/ErrorHandler.h
index f17f7cc99035..c169f7b50de8 100644
--- a/include/lld/Common/ErrorHandler.h
+++ b/include/lld/Common/ErrorHandler.h
@@ -153,7 +153,7 @@ T check2(Expected<T> E, llvm::function_ref<std::string()> Prefix) {
inline std::string toString(const Twine &S) { return S.str(); }
// To evaluate the second argument lazily, we use C macro.
-#define CHECK(E, S) check2(E, [&] { return toString(S); })
+#define CHECK(E, S) check2((E), [&] { return toString(S); })
} // namespace lld
diff --git a/include/lld/Common/LLVM.h b/include/lld/Common/LLVM.h
index b5d0e2bffb03..95a2aa903957 100644
--- a/include/lld/Common/LLVM.h
+++ b/include/lld/Common/LLVM.h
@@ -22,53 +22,69 @@
#include <utility>
namespace llvm {
- // ADT's.
- class Error;
- class StringRef;
- class Twine;
- class MemoryBuffer;
- class MemoryBufferRef;
- template<typename T> class ArrayRef;
- template<unsigned InternalLen> class SmallString;
- template<typename T, unsigned N> class SmallVector;
- template<typename T> class SmallVectorImpl;
+// ADT's.
+class raw_ostream;
+class Error;
+class StringRef;
+class Twine;
+class MemoryBuffer;
+class MemoryBufferRef;
+template <typename T> class ArrayRef;
+template <unsigned InternalLen> class SmallString;
+template <typename T, unsigned N> class SmallVector;
+template <typename T> class ErrorOr;
+template <typename T> class Expected;
- template<typename T>
- struct SaveAndRestore;
+namespace object {
+class WasmObjectFile;
+struct WasmSection;
+struct WasmSegment;
+class WasmSymbol;
+} // namespace object
- template<typename T>
- class ErrorOr;
-
- template<typename T>
- class Expected;
-
- class raw_ostream;
- // TODO: DenseMap, ...
-}
+namespace wasm {
+struct WasmEvent;
+struct WasmEventType;
+struct WasmFunction;
+struct WasmGlobal;
+struct WasmGlobalType;
+struct WasmRelocation;
+struct WasmSignature;
+} // namespace wasm
+} // namespace llvm
namespace lld {
- // Casting operators.
- using llvm::isa;
- using llvm::cast;
- using llvm::dyn_cast;
- using llvm::dyn_cast_or_null;
- using llvm::cast_or_null;
+// Casting operators.
+using llvm::cast;
+using llvm::cast_or_null;
+using llvm::dyn_cast;
+using llvm::dyn_cast_or_null;
+using llvm::isa;
- // ADT's.
- using llvm::Error;
- using llvm::StringRef;
- using llvm::Twine;
- using llvm::MemoryBuffer;
- using llvm::MemoryBufferRef;
- using llvm::ArrayRef;
- using llvm::SmallString;
- using llvm::SmallVector;
- using llvm::SmallVectorImpl;
- using llvm::SaveAndRestore;
- using llvm::ErrorOr;
- using llvm::Expected;
+// ADT's.
+using llvm::ArrayRef;
+using llvm::Error;
+using llvm::ErrorOr;
+using llvm::Expected;
+using llvm::MemoryBuffer;
+using llvm::MemoryBufferRef;
+using llvm::raw_ostream;
+using llvm::SmallString;
+using llvm::SmallVector;
+using llvm::StringRef;
+using llvm::Twine;
- using llvm::raw_ostream;
+using llvm::object::WasmObjectFile;
+using llvm::object::WasmSection;
+using llvm::object::WasmSegment;
+using llvm::object::WasmSymbol;
+using llvm::wasm::WasmEvent;
+using llvm::wasm::WasmEventType;
+using llvm::wasm::WasmFunction;
+using llvm::wasm::WasmGlobal;
+using llvm::wasm::WasmGlobalType;
+using llvm::wasm::WasmRelocation;
+using llvm::wasm::WasmSignature;
} // end namespace lld.
namespace std {
@@ -78,6 +94,6 @@ public:
return llvm::hash_value(s);
}
};
-}
+} // namespace std
#endif
diff --git a/include/lld/Common/Strings.h b/include/lld/Common/Strings.h
index e17b25763781..566030e43aa6 100644
--- a/include/lld/Common/Strings.h
+++ b/include/lld/Common/Strings.h
@@ -41,9 +41,6 @@ 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 8443b184aa70..2eaecb72759e 100644
--- a/include/lld/Common/TargetOptionsCommandFlags.h
+++ b/include/lld/Common/TargetOptionsCommandFlags.h
@@ -19,4 +19,5 @@ namespace lld {
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel();
std::string GetCPUStr();
+std::vector<std::string> GetMAttrs();
}
diff --git a/include/lld/Common/Threads.h b/include/lld/Common/Threads.h
index 854590753143..1425abd12922 100644
--- a/include/lld/Common/Threads.h
+++ b/include/lld/Common/Threads.h
@@ -74,7 +74,7 @@ template <typename R, class FuncTy> void parallelForEach(R &&Range, FuncTy Fn) {
}
inline void parallelForEachN(size_t Begin, size_t End,
- std::function<void(size_t)> Fn) {
+ llvm::function_ref<void(size_t)> Fn) {
if (ThreadsEnabled)
for_each_n(llvm::parallel::par, Begin, End, Fn);
else
diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt
deleted file mode 100644
index 2aa61ff8612d..000000000000
--- a/include/lld/Core/TODO.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-include/lld/Core
-~~~~~~~~~~~~~~~~
-
-* The yaml reader/writer interfaces should be changed to return
- an explanatory string if there is an error. The existing error_code
- abstraction only works for returning low level OS errors. It does not
- work for describing formatting issues.
-
-* We need to add more attributes to File. In particular, we need cpu
- and OS information (like target triples). We should also provide explicit
- support for `LLVM IR module flags metadata`__.
-
-.. __: http://llvm.org/docs/LangRef.html#module_flags
-.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics
diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp
index ad22845207e1..bbac230df453 100644
--- a/lib/Driver/DarwinLdDriver.cpp
+++ b/lib/Driver/DarwinLdDriver.cpp
@@ -382,10 +382,13 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) {
if (arch == MachOLinkingContext::arch_unknown &&
!parsedArgs.getLastArg(OPT_test_file_usage)) {
// If no -arch and no options at all, print usage message.
- if (parsedArgs.size() == 0)
- table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false);
- else
+ if (parsedArgs.size() == 0) {
+ table.PrintHelp(llvm::outs(),
+ (std::string(args[0]) + " [options] file...").c_str(),
+ "LLVM Linker", false);
+ } else {
error("-arch not specified and could not be inferred");
+ }
return false;
}
}
@@ -1143,7 +1146,7 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) {
/// This is where the link is actually performed.
bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = llvm::sys::path::filename(args[0]);
+ errorHandler().LogName = args::getFilenameWithoutExe(args[0]);
errorHandler().ErrorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"'-error-limit 0' to see all errors)";
diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
index 8cb6710857e3..fba3d530e484 100644
--- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
+++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp
@@ -80,6 +80,7 @@ public:
switch (ref->kindValue()) {
case ripRel32Got:
assert(targetNowGOT && "target must be GOT");
+ LLVM_FALLTHROUGH;
case ripRel32GotLoad:
const_cast<Reference *>(ref)
->setKindValue(targetNowGOT ? ripRel32 : ripRel32GotLoadNowLea);
diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index ce423d03aae3..61583963ddd7 100644
--- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -262,6 +262,7 @@ void MachOLinkingContext::configure(HeaderFileType type, Arch arch, OS os,
case llvm::MachO::MH_OBJECT:
_printRemainingUndefines = false;
_allowRemainingUndefines = true;
+ break;
default:
break;
}
diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
index 407bd9b97020..ee9e174b82e0 100644
--- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
+++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
@@ -186,11 +186,10 @@ packRelocation(const Relocation &r, bool swap, bool isBigEndian) {
}
inline StringRef getString16(const char s[16]) {
- StringRef x = s;
- if ( x.size() > 16 )
- return x.substr(0, 16);
- else
- return x;
+ // The StringRef(const char *) constructor passes the const char * to
+ // strlen(), so we can't use this constructor here, because if there is no
+ // null terminator in s, then strlen() will read past the end of the array.
+ return StringRef(s, strnlen(s, 16));
}
inline void setString16(StringRef str, char s[16]) {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 12fb7c3c1e99..1b908335c4a1 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -53,6 +53,9 @@ add_lit_testsuite(check-lld "Running lld test suite"
DEPENDS ${LLD_TEST_DEPS}
)
+add_custom_target(lld-test-depends DEPENDS ${LLD_TEST_DEPS})
+set_target_properties(lld-test-depends PROPERTIES FOLDER "lld tests")
+
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
diff --git a/test/COFF/Inputs/associative-comdat-mingw-2.s b/test/COFF/Inputs/associative-comdat-mingw-2.s
new file mode 100644
index 000000000000..edb6a82da84b
--- /dev/null
+++ b/test/COFF/Inputs/associative-comdat-mingw-2.s
@@ -0,0 +1,34 @@
+ .section .xdata$foo,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 42
+
+ .section .xdata$bar,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 43
+
+ .section .xdata$baz,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 44
+
+ .def foo;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text$foo,"xr",discard,foo
+ .globl foo
+ .p2align 4
+foo:
+ ret
+
+ .def bar;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text$bar,"xr",discard,bar
+ .globl bar
+ .p2align 4
+bar:
+ ret
diff --git a/test/COFF/Inputs/bad-block-size.pdb b/test/COFF/Inputs/bad-block-size.pdb
new file mode 100644
index 000000000000..fadd8833e4bb
--- /dev/null
+++ b/test/COFF/Inputs/bad-block-size.pdb
@@ -0,0 +1,2 @@
+Microsoft C/C++ MSF 7.00
+DS \ No newline at end of file
diff --git a/test/COFF/Inputs/comdat-jumptable2.s b/test/COFF/Inputs/comdat-jumptable2.s
new file mode 100644
index 000000000000..8990d4c0d7f3
--- /dev/null
+++ b/test/COFF/Inputs/comdat-jumptable2.s
@@ -0,0 +1,35 @@
+ .section .text@comdatfunc, "x"
+ .linkonce discard
+ .globl comdatfunc
+comdatfunc:
+ leaq .Ljumptable(%rip), %rax
+ movslq (%rax, %rcx, 4), %rcx
+ addq %rcx, %rax
+ jmp *%rax
+
+ .section .rdata, "dr"
+ .long 0xcccccccc
+.Ljumptable:
+ .long .Ltail1-.Ljumptable
+ .long .Ltail2-.Ljumptable
+ .long .Ltail3-.Ljumptable
+ .long 0xdddddddd
+
+ .section .text@comdatfunc, "x"
+# If assembled with binutils, the following line can be kept in:
+# .linkonce discard
+.Ltail1:
+ movl $1, %eax
+ ret
+.Ltail2:
+ movl $2, %eax
+ ret
+.Ltail3:
+ movl $3, %eax
+ ret
+
+ .text
+ .globl otherfunc
+otherfunc:
+ call comdatfunc
+ ret
diff --git a/test/COFF/Inputs/common-replacement.s b/test/COFF/Inputs/common-replacement.s
new file mode 100644
index 000000000000..eaaeee2a3d36
--- /dev/null
+++ b/test/COFF/Inputs/common-replacement.s
@@ -0,0 +1,5 @@
+ .globl foo
+ .data
+ .p2align 2, 0
+foo:
+ .long 42
diff --git a/test/COFF/Inputs/crt-dyn-initializer-order_1.yaml b/test/COFF/Inputs/crt-dyn-initializer-order_1.yaml
new file mode 100644
index 000000000000..302f6f2feeac
--- /dev/null
+++ b/test/COFF/Inputs/crt-dyn-initializer-order_1.yaml
@@ -0,0 +1,15 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 55
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 70
+symbols:
+...
diff --git a/test/COFF/Inputs/crt-dyn-initializer-order_2.yaml b/test/COFF/Inputs/crt-dyn-initializer-order_2.yaml
new file mode 100644
index 000000000000..a2d0e5e25b1c
--- /dev/null
+++ b/test/COFF/Inputs/crt-dyn-initializer-order_2.yaml
@@ -0,0 +1,19 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 10
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 11
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 12
+symbols:
+...
diff --git a/test/COFF/Inputs/empty.yaml b/test/COFF/Inputs/empty.yaml
new file mode 100644
index 000000000000..6396f8aed08a
--- /dev/null
+++ b/test/COFF/Inputs/empty.yaml
@@ -0,0 +1,67 @@
+--- !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: 31C0C3
+ - 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: ''
+symbols:
+ - Name: .text
+ 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: .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: '@feat.00'
+ Value: 1
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: _main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/Inputs/far-arm-thumb-abs.s b/test/COFF/Inputs/far-arm-thumb-abs.s
deleted file mode 100644
index 9f1b59a55f8c..000000000000
--- a/test/COFF/Inputs/far-arm-thumb-abs.s
+++ /dev/null
@@ -1,2 +0,0 @@
-.global too_far1
-too_far1 = 0x1401004
diff --git a/test/COFF/Inputs/far-arm-thumb-abs20.s b/test/COFF/Inputs/far-arm-thumb-abs20.s
deleted file mode 100644
index 8483e32dc7f0..000000000000
--- a/test/COFF/Inputs/far-arm-thumb-abs20.s
+++ /dev/null
@@ -1,2 +0,0 @@
-.global too_far20
-too_far20 = 0x501004
diff --git a/test/COFF/Inputs/gnu-implib-data.s b/test/COFF/Inputs/gnu-implib-data.s
new file mode 100644
index 000000000000..d9af7756332c
--- /dev/null
+++ b/test/COFF/Inputs/gnu-implib-data.s
@@ -0,0 +1,23 @@
+ .global __imp_data
+
+ # The data that is emitted into .idata$7 here is isn't needed for
+ # the import data structures, but we need to emit something which
+ # produces a relocation against _head_test_lib, to pull in the
+ # header and trailer objects.
+
+ .section .idata$7
+ .rva _head_test_lib
+
+ .section .idata$5
+__imp_data:
+ .rva .Lhint_name
+ .long 0
+
+ .section .idata$4
+ .rva .Lhint_name
+ .long 0
+
+ .section .idata$6
+.Lhint_name:
+ .short 0
+ .asciz "data"
diff --git a/test/COFF/Inputs/gnu-implib-func.s b/test/COFF/Inputs/gnu-implib-func.s
new file mode 100644
index 000000000000..5f37ee1cd223
--- /dev/null
+++ b/test/COFF/Inputs/gnu-implib-func.s
@@ -0,0 +1,27 @@
+ .text
+ .global func
+ .global __imp_func
+func:
+ jmp *__imp_func
+
+ # The data that is emitted into .idata$7 here is isn't needed for
+ # the import data structures, but we need to emit something which
+ # produces a relocation against _head_test_lib, to pull in the
+ # header and trailer objects.
+
+ .section .idata$7
+ .rva _head_test_lib
+
+ .section .idata$5
+__imp_func:
+ .rva .Lhint_name
+ .long 0
+
+ .section .idata$4
+ .rva .Lhint_name
+ .long 0
+
+ .section .idata$6
+.Lhint_name:
+ .short 0
+ .asciz "func"
diff --git a/test/COFF/Inputs/gnu-implib-head.s b/test/COFF/Inputs/gnu-implib-head.s
new file mode 100644
index 000000000000..b32acf0d6f3d
--- /dev/null
+++ b/test/COFF/Inputs/gnu-implib-head.s
@@ -0,0 +1,13 @@
+ .section .idata$2
+ .global _head_test_lib
+_head_test_lib:
+ .rva hname
+ .long 0
+ .long 0
+ .rva __test_lib_iname
+ .rva fthunk
+
+ .section .idata$5
+fthunk:
+ .section .idata$4
+hname:
diff --git a/test/COFF/Inputs/gnu-implib-tail.s b/test/COFF/Inputs/gnu-implib-tail.s
new file mode 100644
index 000000000000..784d51f6e830
--- /dev/null
+++ b/test/COFF/Inputs/gnu-implib-tail.s
@@ -0,0 +1,11 @@
+ .section .idata$4
+ .long 0
+ .long 0
+ .section .idata$5
+ .long 0
+ .long 0
+
+ .section .idata$7
+ .global __test_lib_iname
+__test_lib_iname:
+ .asciz "foo.dll"
diff --git a/test/COFF/Inputs/gnu-weak.o b/test/COFF/Inputs/gnu-weak.o
new file mode 100644
index 000000000000..997f00463560
--- /dev/null
+++ b/test/COFF/Inputs/gnu-weak.o
Binary files differ
diff --git a/test/COFF/Inputs/gnu-weak2.o b/test/COFF/Inputs/gnu-weak2.o
new file mode 100644
index 000000000000..15b5d4dad93f
--- /dev/null
+++ b/test/COFF/Inputs/gnu-weak2.o
Binary files differ
diff --git a/test/COFF/Inputs/icf-safe.s b/test/COFF/Inputs/icf-safe.s
new file mode 100644
index 000000000000..3a2b3b18e7ab
--- /dev/null
+++ b/test/COFF/Inputs/icf-safe.s
@@ -0,0 +1,9 @@
+.section .rdata,"dr",one_only,non_addrsig1
+.globl non_addrsig1
+non_addrsig1:
+.byte 3
+
+.section .rdata,"dr",one_only,non_addrsig2
+.globl non_addrsig2
+non_addrsig2:
+.byte 3
diff --git a/test/COFF/Inputs/inline-weak.o b/test/COFF/Inputs/inline-weak.o
new file mode 100644
index 000000000000..5987e60fd657
--- /dev/null
+++ b/test/COFF/Inputs/inline-weak.o
Binary files differ
diff --git a/test/COFF/Inputs/inline-weak2.o b/test/COFF/Inputs/inline-weak2.o
new file mode 100644
index 000000000000..b413f5bb0d43
--- /dev/null
+++ b/test/COFF/Inputs/inline-weak2.o
Binary files differ
diff --git a/test/COFF/Inputs/pdb-file-statics-a.yaml b/test/COFF/Inputs/pdb-file-statics-a.yaml
index 957eb5aee869..1a0dbdb67855 100644
--- a/test/COFF/Inputs/pdb-file-statics-a.yaml
+++ b/test/COFF/Inputs/pdb-file-statics-a.yaml
@@ -1353,7 +1353,7 @@ sections:
RegRelativeSym:
Offset: 48
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -1528,13 +1528,13 @@ sections:
RegRelativeSym:
Offset: 48
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: argc
- Kind: S_REGREL32
RegRelativeSym:
Offset: 56
Type: 4098
- Register: CVRegRSP
+ Register: RSP
VarName: argv
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-file-statics-b.yaml b/test/COFF/Inputs/pdb-file-statics-b.yaml
index 8b7a311f0f8b..f74bab703477 100644
--- a/test/COFF/Inputs/pdb-file-statics-b.yaml
+++ b/test/COFF/Inputs/pdb-file-statics-b.yaml
@@ -1328,7 +1328,7 @@ sections:
RegRelativeSym:
Offset: 48
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml
index 0fc41723bdc2..e422a6241f27 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: CVRegRSP
+ Register: RSP
VarName: x
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -93,7 +93,7 @@ sections:
RegRelativeSym:
Offset: 64
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: argc
- Kind: S_BLOCK32
BlockSym:
@@ -104,7 +104,7 @@ sections:
RegRelativeSym:
Offset: 32
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: x
- Kind: S_END
ScopeEndSym:
@@ -117,7 +117,7 @@ sections:
RegRelativeSym:
Offset: 36
Type: 116
- Register: CVRegRSP
+ Register: RSP
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 c0ee98b0d64c..b1c602143c3f 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: CVRegRSP
+ Register: RSP
VarName: x
- Kind: S_BLOCK32
BlockSym:
@@ -64,7 +64,7 @@ sections:
RegRelativeSym:
Offset: 32
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: y
- Kind: S_END
ScopeEndSym:
@@ -77,7 +77,7 @@ sections:
RegRelativeSym:
Offset: 36
Type: 116
- Register: CVRegRSP
+ Register: RSP
VarName: w
- Kind: S_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-missing-2.yaml b/test/COFF/Inputs/pdb-type-server-missing-2.yaml
new file mode 100644
index 000000000000..e71bcec22448
--- /dev/null
+++ b/test/COFF/Inputs/pdb-type-server-missing-2.yaml
@@ -0,0 +1,32 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Types:
+ - Kind: LF_TYPESERVER2
+ TypeServer2:
+ Guid: '{01DF191B-22BF-6B42-96CE-5258B8329FE5}'
+ Age: 18
+ Name: 'C:\src\llvm-project\build\definitely_not_found_for_sure.pdb'
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 33C0C3
+symbols:
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 564
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+...
diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml
index 8425c4f63b70..78c68168127b 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: CVRegRSP
+ Register: RSP
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 3b511cb0d861..56e97d530894 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: CVRegRSP
+ Register: RSP
VarName: p
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/Inputs/pdb-type-server-valid-signature.yaml b/test/COFF/Inputs/pdb-type-server-valid-signature.yaml
new file mode 100644
index 000000000000..dd95a3df8893
--- /dev/null
+++ b/test/COFF/Inputs/pdb-type-server-valid-signature.yaml
@@ -0,0 +1,121 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 3
+ DbgStart: 0
+ DbgEnd: 2
+ FunctionType: 4199
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 0
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 3
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Lines:
+ - Offset: 0
+ LineStart: 1
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Kind: MD5
+ Checksum: 270A878DCC1B845655B162F56C4F5020
+ - !StringTable
+ Strings:
+ - 'c:\src\llvm-project\build\t.c'
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 100
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ 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: 1
+ Types:
+ - Kind: LF_TYPESERVER2
+ TypeServer2:
+ Guid: '{8DABD2A0-28FF-CB43-9BAF-175B77B76414}'
+ Age: 18
+ Name: 'pdb-diff-cl.pdb'
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 33C0C3
+symbols:
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 328
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 564
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 3
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 4021952397
+ Number: 0
+ - Name: main
+ 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/precomp-a.obj b/test/COFF/Inputs/precomp-a.obj
new file mode 100644
index 000000000000..b63392a7a86f
--- /dev/null
+++ b/test/COFF/Inputs/precomp-a.obj
Binary files differ
diff --git a/test/COFF/Inputs/precomp-b.obj b/test/COFF/Inputs/precomp-b.obj
new file mode 100644
index 000000000000..d590ecebe288
--- /dev/null
+++ b/test/COFF/Inputs/precomp-b.obj
Binary files differ
diff --git a/test/COFF/Inputs/precomp-invalid.obj b/test/COFF/Inputs/precomp-invalid.obj
new file mode 100644
index 000000000000..2ad270a6e616
--- /dev/null
+++ b/test/COFF/Inputs/precomp-invalid.obj
Binary files differ
diff --git a/test/COFF/Inputs/precomp.obj b/test/COFF/Inputs/precomp.obj
new file mode 100644
index 000000000000..424077e68dc5
--- /dev/null
+++ b/test/COFF/Inputs/precomp.obj
Binary files differ
diff --git a/test/COFF/arm-thumb-branch-error.s b/test/COFF/arm-thumb-branch-error.s
deleted file mode 100644
index 00b835c58a15..000000000000
--- a/test/COFF/arm-thumb-branch-error.s
+++ /dev/null
@@ -1,10 +0,0 @@
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %S/Inputs/far-arm-thumb-abs.s -o %tfar
-// RUN: not lld-link -entry:_start -subsystem:console %t %tfar -out:%t2 2>&1 | FileCheck %s
-// REQUIRES: arm
- .syntax unified
- .globl _start
-_start:
- bl too_far1
-
-// CHECK: relocation out of range
diff --git a/test/COFF/arm-thumb-branch20-error.s b/test/COFF/arm-thumb-branch20-error.s
index ec7d23b05329..fbbc0d49d02b 100644
--- a/test/COFF/arm-thumb-branch20-error.s
+++ b/test/COFF/arm-thumb-branch20-error.s
@@ -1,10 +1,16 @@
// REQUIRES: arm
// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %s -o %t.obj
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-windows-gnu %S/Inputs/far-arm-thumb-abs20.s -o %t.far.obj
-// RUN: not lld-link -entry:_start -subsystem:console %t.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s
+// RUN: not lld-link -entry:_start -subsystem:console %t.obj -out:%t.exe 2>&1 | FileCheck %s
.syntax unified
.globl _start
_start:
bne too_far20
+ .space 0x100000
+ .section .text$a, "xr"
+too_far20:
+ bx lr
-// CHECK: relocation out of range
+// When trying to add a thunk at the end of the section, the thunk itself
+// will be too far away, so this won't converge.
+
+// CHECK: adding thunks hasn't converged
diff --git a/test/COFF/arm-thumb-thunks-multipass.s b/test/COFF/arm-thumb-thunks-multipass.s
new file mode 100644
index 000000000000..5e64e8df49c8
--- /dev/null
+++ b/test/COFF/arm-thumb-thunks-multipass.s
@@ -0,0 +1,70 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x403000 -stop-address=0x403008 | FileCheck -check-prefix=FUNC01 %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x404ffa -stop-address=0x405012 | FileCheck -check-prefix=FUNC01-THUNKS %s
+
+// VERBOSE: Added {{.*}} thunks with margin 204800 in 2 passes
+
+ .syntax unified
+ .globl main
+ .text
+main:
+ b func01
+ bx lr
+
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+ .section .text$\i\()a, "xr"
+ .balign 8192
+func\i:
+ bne far_func\i
+ bne func_within_margin\i
+ // Originally, the first section is less than 8192 bytes large, and the
+ // second one follows almost directly. After adding one thunk after
+ // the first section, the second one will move forward by 8192 bytes
+ // due to the alignment.
+ .space 8192 - 8 - 4
+
+ .section .text$\i\()b, "xr"
+ .balign 8192
+align\i:
+ nop
+.endr
+
+ .section .text$999, "xr"
+tail:
+ .space 0x100000 - 100*1024 - 18*8192*2
+ // Initially, these symbols are within range from all the sections above,
+ // even when taking the initial margin into account. After adding thunks
+ // to all the sections above, some of these are also out of range, forcing
+ // running a second pass.
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+func_within_margin\i:
+ nop
+.endr
+ .space 0x100000
+
+ // These are always out of range.
+.irp i, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18
+far_func\i:
+ nop
+.endr
+ bx lr
+
+// FUNC01: 403000: 41 f0 fc 87 bne.w #8184 <.text+0x3ffc>
+// FUNC01: 403004: 41 f0 ff 87 bne.w #8190 <.text+0x4006>
+
+// Check that we only have two thunks here, even if we created the first
+// thunk twice (once in the first pass, then thrown away and recreated
+// in the second pass).
+
+// FUNC01-THUNKS: 404ffa: 00 00 movs r0, r0
+// The instruction above is padding from the .space
+// FUNC01-THUNKS: 404ffc: 47 f2 1e 0c movw r12, #28702
+// FUNC01-THUNKS: 405000: c0 f2 20 0c movt r12, #32
+// FUNC01-THUNKS: 405004: e7 44 add pc, r12
+// FUNC01-THUNKS: 405006: 46 f6 f0 7c movw r12, #28656
+// FUNC01-THUNKS: 40500a: c0 f2 10 0c movt r12, #16
+// FUNC01-THUNKS: 40500e: e7 44 add pc, r12
+// The instruction below is padding from the .balign
+// FUNC01-THUNKS: 405010: cc cc ldm r4!, {r2, r3, r6, r7}
diff --git a/test/COFF/arm-thumb-thunks.s b/test/COFF/arm-thumb-thunks.s
new file mode 100644
index 000000000000..33c3740ba8cb
--- /dev/null
+++ b/test/COFF/arm-thumb-thunks.s
@@ -0,0 +1,75 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=thumbv7-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe -verbose 2>&1 | FileCheck -check-prefix=VERBOSE %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x401000 -stop-address=0x401022 | FileCheck -check-prefix=MAIN %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x501022 -stop-address=0x501032 | FileCheck -check-prefix=FUNC1 %s
+// RUN: llvm-objdump -d %t.exe -start-address=0x601032 | FileCheck -check-prefix=FUNC2 %s
+
+// VERBOSE: Added 3 thunks with margin {{.*}} in 1 passes
+
+ .syntax unified
+ .globl main
+ .globl func1
+ .text
+main:
+ bne func1
+ bne func2
+ // This should reuse the same thunk as func1 above
+ bne func1_alias
+ bx lr
+ .section .text$a, "xr"
+ .space 0x100000
+ .section .text$b, "xr"
+func1:
+func1_alias:
+ // This shouldn't reuse the func2 thunk from above, since it is out
+ // of range.
+ bne func2
+ bx lr
+ .section .text$c, "xr"
+ .space 0x100000
+ .section .text$d, "xr"
+func2:
+// Test using string tail merging. This is irrelevant to the thunking itself,
+// but running multiple passes of assignAddresses() calls finalizeAddresses()
+// multiple times; check that MergeChunk handles this correctly.
+ movw r0, :lower16:"??_C@string1"
+ movt r0, :upper16:"??_C@string1"
+ movw r1, :lower16:"??_C@string2"
+ movt r1, :upper16:"??_C@string2"
+ bx lr
+
+ .section .rdata,"dr",discard,"??_C@string1"
+ .globl "??_C@string1"
+"??_C@string1":
+ .asciz "foobar"
+ .section .rdata,"dr",discard,"??_C@string2"
+ .globl "??_C@string2"
+"??_C@string2":
+ .asciz "bar"
+
+// MAIN: 401000: 40 f0 05 80 bne.w #10 <.text+0xe>
+// MAIN: 401004: 40 f0 08 80 bne.w #16 <.text+0x18>
+// MAIN: 401008: 40 f0 01 80 bne.w #2 <.text+0xe>
+// MAIN: 40100c: 70 47 bx lr
+// func1 thunk
+// MAIN: 40100e: 40 f2 08 0c movw r12, #8
+// MAIN: 401012: c0 f2 10 0c movt r12, #16
+// MAIN: 401016: e7 44 add pc, r12
+// func2 thunk
+// MAIN: 401018: 40 f2 0e 0c movw r12, #14
+// MAIN: 40101c: c0 f2 20 0c movt r12, #32
+// MAIN: 401020: e7 44 add pc, r12
+
+// FUNC1: 501022: 40 f0 01 80 bne.w #2 <.text+0x100028>
+// FUNC1: 501026: 70 47 bx lr
+// func2 thunk
+// FUNC1: 501028: 4f f6 fe 7c movw r12, #65534
+// FUNC1: 50102c: c0 f2 0f 0c movt r12, #15
+// FUNC1: 501030: e7 44 add pc, r12
+
+// FUNC2: 601032: 42 f2 00 00 movw r0, #8192
+// FUNC2: 601036: c0 f2 60 00 movt r0, #96
+// FUNC2: 60103a: 42 f2 03 01 movw r1, #8195
+// FUNC2: 60103e: c0 f2 60 01 movt r1, #96
+// FUNC2: 601042: 70 47 bx lr
diff --git a/test/COFF/arm64-delayimport.yaml b/test/COFF/arm64-delayimport.yaml
new file mode 100644
index 000000000000..6d3d70564c04
--- /dev/null
+++ b/test/COFF/arm64-delayimport.yaml
@@ -0,0 +1,91 @@
+# REQUIRES: aarch64
+
+# RUN: yaml2obj < %s > %t.obj
+# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib /alternatename:__delayLoadHelper2=main /delayload:library.dll
+# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix DISASM
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s -check-prefix IMPORTS
+
+# DISASM: 140001014: 11 00 00 d0 adrp x17, #8192
+# DISASM: 140001018: 31 22 00 91 add x17, x17, #8
+# DISASM: 14000101c: fd 7b b3 a9 stp x29, x30, [sp, #-208]!
+# DISASM: 140001020: fd 03 00 91 mov x29, sp
+# DISASM: 140001024: e0 07 01 a9 stp x0, x1, [sp, #16]
+# DISASM: 140001028: e2 0f 02 a9 stp x2, x3, [sp, #32]
+# DISASM: 14000102c: e4 17 03 a9 stp x4, x5, [sp, #48]
+# DISASM: 140001030: e6 1f 04 a9 stp x6, x7, [sp, #64]
+# DISASM: 140001034: e0 87 02 ad stp q0, q1, [sp, #80]
+# DISASM: 140001038: e2 8f 03 ad stp q2, q3, [sp, #112]
+# DISASM: 14000103c: e4 97 04 ad stp q4, q5, [sp, #144]
+# DISASM: 140001040: e6 9f 05 ad stp q6, q7, [sp, #176]
+# DISASM: 140001044: e1 03 11 aa mov x1, x17
+# DISASM: 140001048: 00 00 00 b0 adrp x0, #4096
+# DISASM: 14000104c: 00 00 00 91 add x0, x0, #0
+# DISASM: 140001050: ec ff ff 97 bl #-80 <.text>
+# DISASM: 140001054: f0 03 00 aa mov x16, x0
+# DISASM: 140001058: e6 9f 45 ad ldp q6, q7, [sp, #176]
+# DISASM: 14000105c: e4 97 44 ad ldp q4, q5, [sp, #144]
+# DISASM: 140001060: e2 8f 43 ad ldp q2, q3, [sp, #112]
+# DISASM: 140001064: e0 87 42 ad ldp q0, q1, [sp, #80]
+# DISASM: 140001068: e6 1f 44 a9 ldp x6, x7, [sp, #64]
+# DISASM: 14000106c: e4 17 43 a9 ldp x4, x5, [sp, #48]
+# DISASM: 140001070: e2 0f 42 a9 ldp x2, x3, [sp, #32]
+# DISASM: 140001074: e0 07 41 a9 ldp x0, x1, [sp, #16]
+# DISASM: 140001078: fd 7b cd a8 ldp x29, x30, [sp], #208
+# DISASM: 14000107c: 00 02 1f d6 br x16
+
+# IMPORTS: Format: COFF-ARM64
+# IMPORTS: Arch: aarch64
+# IMPORTS: AddressSize: 64bit
+# IMPORTS: DelayImport {
+# IMPORTS: Name: library.dll
+# IMPORTS: Attributes: 0x1
+# IMPORTS: ModuleHandle: 0x3000
+# IMPORTS: ImportAddressTable: 0x3008
+# IMPORTS: ImportNameTable: 0x2040
+# IMPORTS: BoundDelayImportTable: 0x0
+# IMPORTS: UnloadDelayImportTable: 0x0
+# IMPORTS: Import {
+# IMPORTS: Symbol: function (0)
+# IMPORTS: Address: 0x140001014
+# IMPORTS: }
+# IMPORTS: }
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_ARM64
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 00000094C0035FD6
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: function
+ Type: IMAGE_REL_ARM64_BRANCH26
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 8
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 1
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: function
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/arm64-localimport-align.s b/test/COFF/arm64-localimport-align.s
new file mode 100644
index 000000000000..4fbc79ec36d7
--- /dev/null
+++ b/test/COFF/arm64-localimport-align.s
@@ -0,0 +1,24 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe
+// Don't check the output, just make sure it links fine and doesn't
+// error out due to a misaligned load.
+ .text
+ .globl main
+ .globl myfunc
+main:
+ adrp x8, __imp_myfunc
+ ldr x0, [x8, :lo12:__imp_myfunc]
+ br x0
+ ret
+myfunc:
+ ret
+
+ .section .rdata, "dr"
+ // Start the .rdata section with a 4 byte chunk, to expose the alignment
+ // of the next chunk in the section.
+mydata:
+ .byte 42
+ // The synthesized LocalImportChunk gets stored here in the .rdata
+ // section, but needs to get proper 8 byte alignment since it is a
+ // pointer, just like regular LookupChunks in the IAT.
diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test
index c7b8b7c28466..e2c00f189fef 100644
--- a/test/COFF/arm64-relocs-imports.test
+++ b/test/COFF/arm64-relocs-imports.test
@@ -34,14 +34,14 @@
# BEFORE: 64: e0 03 1f 2a mov w0, wzr
# BEFORE: 68: fe 07 41 f8 ldr x30, [sp], #16
# BEFORE: 6c: c0 03 5f d6 ret
-# BEFORE: 70: 08 00 00 00 <unknown>
-# BEFORE: 74: 00 00 00 00 <unknown>
-# BEFORE: 78: 01 00 00 00 <unknown>
-# BEFORE: 7c: 01 00 00 00 <unknown>
+# BEFORE: 70: 08 00 00 00 udf #8
+# BEFORE: 74: 00 00 00 00 udf #0
+# BEFORE: 78: 01 00 00 00 udf #1
+# BEFORE: 7c: 01 00 00 00 udf #1
# 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: 8c: 01 00 00 00 udf #1
# 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
@@ -76,13 +76,13 @@
# 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: 140001074: 01 00 00 00 udf #1
+# AFTER: 140001078: 09 20 00 00 udf #8201
+# AFTER: 14000107c: 09 00 00 00 udf #9
# 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: 14000108c: 03 00 00 00 udf #3
# 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
diff --git a/test/COFF/associative-comdat-mingw.s b/test/COFF/associative-comdat-mingw.s
new file mode 100644
index 000000000000..def20cd85294
--- /dev/null
+++ b/test/COFF/associative-comdat-mingw.s
@@ -0,0 +1,74 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t1.obj
+# RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/associative-comdat-mingw-2.s -filetype=obj -o %t2.obj
+
+# RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.gc.exe -verbose
+# RUN: llvm-readobj -sections %t.gc.exe | FileCheck %s
+
+# CHECK: Sections [
+# 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
+# .xdata$foo was retained. This *must* be 0x24 (0x4 for the .xdata
+# section and 0x20 for the .ctors/.dtors headers/ends).
+# Make sure that no other .xdata sections get included, which would
+# increase the size here.
+# CHECK-NEXT: VirtualSize: 0x24
+
+ .text
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl main
+ .p2align 4, 0x90
+main:
+ call foo
+ retq
+
+# Defines .text$foo (which has a leader symbol and is referenced like
+# normally), and .xdata$foo (which lacks a leader symbol, which normally
+# would be declared associative to the symbol foo).
+# .xdata$foo should be implicitly treated as associative to foo and brought
+# in, while .xdata$bar, implicitly associative to bar, not included, and
+# .xdata$baz not included since there's no symbol baz.
+
+# GNU binutils ld doesn't do this at all, but always includes all .xdata/.pdata
+# comdat sections, even if --gc-sections is used.
+
+ .section .xdata$foo,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 42
+
+ .section .xdata$bar,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 43
+
+ .section .xdata$baz,"dr"
+ .linkonce discard
+ .p2align 3
+ .long 44
+
+ .def foo;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text$foo,"xr",discard,foo
+ .globl foo
+ .p2align 4
+foo:
+ ret
+
+ .def bar;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text$bar,"xr",discard,bar
+ .globl bar
+ .p2align 4
+bar:
+ ret
diff --git a/test/COFF/autoimport-arm-code.s b/test/COFF/autoimport-arm-code.s
new file mode 100644
index 000000000000..562a1a959e38
--- /dev/null
+++ b/test/COFF/autoimport-arm-code.s
@@ -0,0 +1,19 @@
+# REQUIRES: arm
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.thumb\n.text\nDllMainCRTStartup:\nbx lr\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=armv7-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=armv7-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: not lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib 2>&1 | FileCheck %s
+
+# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM_MOV32T
+
+ .global main
+ .text
+ .thumb
+main:
+ movw r0, :lower16:variable
+ movt r0, :upper16:variable
+ ldr r0, [r0]
+ bx lr
diff --git a/test/COFF/autoimport-arm-data.s b/test/COFF/autoimport-arm-data.s
new file mode 100644
index 000000000000..945d51c9423c
--- /dev/null
+++ b/test/COFF/autoimport-arm-data.s
@@ -0,0 +1,42 @@
+# REQUIRES: arm
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.thumb\n.text\nDllMainCRTStartup:\nbx lr\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=armv7-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=armv7-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose
+
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s
+
+# IMPORTS: Import {
+# IMPORTS-NEXT: Name: autoimport-arm-data.s.tmp-lib.dll
+# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050
+# IMPORTS-NEXT: ImportAddressTableRVA: 0x2058
+# IMPORTS-NEXT: Symbol: variable (0)
+# IMPORTS-NEXT: }
+
+# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1.
+# First runtime pseudo reloc, with import from 0x2058,
+# applied at 0x3000, with a size of 32 bits.
+# CONTENTS: Contents of section .rdata:
+# CONTENTS: 402000 00000000 00000000 01000000 58200000
+# CONTENTS: 402010 00300000 20000000
+# ptr: pointing at the IAT RVA at 0x2058
+# relocs: pointing at the runtime pseudo reloc list at
+# 0x2000 - 0x2018.
+# CONTENTS: Contents of section .data:
+# CONTENTS: 403000 58204000 00204000 18204000
+
+ .global main
+ .text
+ .thumb
+main:
+ bx lr
+ .data
+ptr:
+ .long variable
+relocs:
+ .long __RUNTIME_PSEUDO_RELOC_LIST__
+ .long __RUNTIME_PSEUDO_RELOC_LIST_END__
diff --git a/test/COFF/autoimport-arm64-code.s b/test/COFF/autoimport-arm64-code.s
new file mode 100644
index 000000000000..9f5cc8f89425
--- /dev/null
+++ b/test/COFF/autoimport-arm64-code.s
@@ -0,0 +1,18 @@
+# REQUIRES: aarch64
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=aarch64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=aarch64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: not lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib 2>&1 | FileCheck %s
+
+# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM64_PAGEBASE_REL21
+# CHECK: error: unable to automatically import from variable with relocation type IMAGE_REL_ARM64_PAGEOFFSET_12L
+
+ .global main
+ .text
+main:
+ adrp x0, variable
+ ldr w0, [x0, :lo12:variable]
+ ret
diff --git a/test/COFF/autoimport-arm64-data.s b/test/COFF/autoimport-arm64-data.s
new file mode 100644
index 000000000000..be4d8706fe3a
--- /dev/null
+++ b/test/COFF/autoimport-arm64-data.s
@@ -0,0 +1,42 @@
+# REQUIRES: aarch64
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=aarch64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=aarch64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose
+
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s
+
+# IMPORTS: Import {
+# IMPORTS-NEXT: Name: autoimport-arm64-data.s.tmp-lib.dll
+# IMPORTS-NEXT: ImportLookupTableRVA: 0x2060
+# IMPORTS-NEXT: ImportAddressTableRVA: 0x2070
+# IMPORTS-NEXT: Symbol: variable (0)
+# IMPORTS-NEXT: }
+
+# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1.
+# First runtime pseudo reloc, with import from 0x2070,
+# applied at 0x3000, with a size of 32 bits.
+# CONTENTS: Contents of section .rdata:
+# CONTENTS: 140002000 00000000 00000000 01000000 70200000
+# CONTENTS: 140002010 00300000 40000000
+# ptr: pointing at the IAT RVA at 0x2070
+# relocs: pointing at the runtime pseudo reloc list at
+# 0x2000 - 0x2018.
+# CONTENTS: Contents of section .data:
+# CONTENTS: 140003000 70200040 01000000 00200040 01000000
+# CONTENTS: 140003010 18200040 01000000
+
+ .global main
+ .text
+main:
+ ret
+ .data
+ptr:
+ .quad variable
+relocs:
+ .quad __RUNTIME_PSEUDO_RELOC_LIST__
+ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__
diff --git a/test/COFF/autoimport-gnu-implib.s b/test/COFF/autoimport-gnu-implib.s
new file mode 100644
index 000000000000..375e0a5857e5
--- /dev/null
+++ b/test/COFF/autoimport-gnu-implib.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-head.s -filetype=obj -o %t-dabcdh.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-data.s -filetype=obj -o %t-dabcds00000.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-tail.s -filetype=obj -o %t-dabcdt.o
+# RUN: rm -f %t-implib.a
+# RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-implib.a -verbose
+
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+
+# IMPORTS: Import {
+# IMPORTS-NEXT: Name: foo.dll
+# IMPORTS-NEXT: ImportLookupTableRVA:
+# IMPORTS-NEXT: ImportAddressTableRVA:
+# IMPORTS-NEXT: Symbol: data (0)
+# IMPORTS-NEXT: }
+
+ .global main
+ .text
+main:
+ movl data(%rip), %eax
+ ret
+ .data
diff --git a/test/COFF/autoimport-list-ptrs.s b/test/COFF/autoimport-list-ptrs.s
new file mode 100644
index 000000000000..d3c9d3d07dbb
--- /dev/null
+++ b/test/COFF/autoimport-list-ptrs.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj -verbose
+
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s
+
+# Even if we didn't actually write any pseudo relocations,
+# check that the synthetic pointers still are set to a non-null value
+# CONTENTS: Contents of section .data:
+# CONTENTS: 140003000 00200040 01000000 00200040 01000000
+
+ .global main
+ .text
+main:
+ retq
+ .data
+relocs:
+ .quad __RUNTIME_PSEUDO_RELOC_LIST__
+ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__
diff --git a/test/COFF/autoimport-refptr.s b/test/COFF/autoimport-refptr.s
new file mode 100644
index 000000000000..4b11a8adde84
--- /dev/null
+++ b/test/COFF/autoimport-refptr.s
@@ -0,0 +1,65 @@
+# REQUIRES: x86
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose
+
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s
+
+# IMPORTS: Import {
+# IMPORTS-NEXT: Name: autoimport-refptr.s.tmp-lib.dll
+# IMPORTS-NEXT: ImportLookupTableRVA: 0x2050
+# IMPORTS-NEXT: ImportAddressTableRVA: 0x2060
+# IMPORTS-NEXT: Symbol: variable (0)
+# IMPORTS-NEXT: }
+
+# DISASM: Disassembly of section .text:
+# DISASM: .text:
+# Relative offset at 0x1002 pointing at the IAT at 0x2060
+# DISASM: 140001000: 48 8b 05 59 10 00 00 movq 4185(%rip), %rax
+# DISASM: 140001007: 8b 00 movl (%rax), %eax
+# Relative offset at 0x100b pointing at the .refptr.localvar stub at
+# 0x2000
+# DISASM: 140001009: 48 8b 0d f0 0f 00 00 movq 4080(%rip), %rcx
+# DISASM: 140001010: 03 01 addl (%rcx), %eax
+# DISASM: 140001012: c3 retq
+
+# relocs: pointing at an empty list of runtime pseudo relocs.
+# localvar: 42
+# CONTENTS: Contents of section .data:
+# CONTENTS: 140003000 08200040 01000000 08200040 01000000
+# CONTENTS: 140003010 2a000000
+
+ .global main
+ .global localvar
+ .text
+main:
+ movq .refptr.variable(%rip), %rax
+ movl (%rax), %eax
+ movq .refptr.localvar(%rip), %rcx
+ addl (%rcx), %eax
+ ret
+
+ .data
+relocs:
+ .quad __RUNTIME_PSEUDO_RELOC_LIST__
+ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__
+localvar:
+ .int 42
+
+# Normally the compiler wouldn't emit a stub for a variable that is
+# emitted in the same translation unit.
+ .section .rdata$.refptr.localvar,"dr",discard,.refptr.localvar
+ .global .refptr.localvar
+.refptr.localvar:
+ .quad localvar
+
+ .section .rdata$.refptr.variable,"dr",discard,.refptr.variable
+ .global .refptr.variable
+.refptr.variable:
+ .quad variable
diff --git a/test/COFF/autoimport-x86.s b/test/COFF/autoimport-x86.s
new file mode 100644
index 000000000000..379985e88097
--- /dev/null
+++ b/test/COFF/autoimport-x86.s
@@ -0,0 +1,53 @@
+# REQUIRES: x86
+
+# RUN: echo -e ".global variable\n.global DllMainCRTStartup\n.text\nDllMainCRTStartup:\nret\n.data\nvariable:\n.long 42" > %t-lib.s
+# RUN: llvm-mc -triple=x86_64-windows-gnu %t-lib.s -filetype=obj -o %t-lib.obj
+# RUN: lld-link -out:%t-lib.dll -dll -entry:DllMainCRTStartup %t-lib.obj -lldmingw -implib:%t-lib.lib
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -lldmingw -out:%t.exe -entry:main %t.obj %t-lib.lib -verbose
+
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORTS %s
+# RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=CONTENTS %s
+
+# IMPORTS: Import {
+# IMPORTS-NEXT: Name: autoimport-x86.s.tmp-lib.dll
+# IMPORTS-NEXT: ImportLookupTableRVA: 0x2070
+# IMPORTS-NEXT: ImportAddressTableRVA: 0x2080
+# IMPORTS-NEXT: Symbol: variable (0)
+# IMPORTS-NEXT: }
+
+# DISASM: Disassembly of section .text:
+# DISASM: .text:
+# Relative offset at 0x1002 pointing at the IAT at 0x2080.
+# DISASM: 140001000: 8b 05 7a 10 00 00 movl 4218(%rip), %eax
+# DISASM: 140001006: c3 retq
+
+# Runtime pseudo reloc list header consisting of 0x0, 0x0, 0x1.
+# First runtime pseudo reloc, with import from 0x2080,
+# applied at 0x1002, with a size of 32 bits.
+# Second runtime pseudo reloc, with import from 0x2080,
+# applied at 0x3000, with a size of 64 bits.
+# CONTENTS: Contents of section .rdata:
+# CONTENTS: 140002000 00000000 00000000 01000000 80200000
+# CONTENTS: 140002010 02100000 20000000 80200000 00300000
+# CONTENTS: 140002020 40000000
+# ptr: pointing at the IAT RVA at 0x2080
+# relocs: pointing at the runtime pseudo reloc list at
+# 0x2000 - 0x2024.
+# CONTENTS: Contents of section .data:
+# CONTENTS: 140003000 80200040 01000000 00200040 01000000
+# CONTENTS: 140003010 24200040 01000000
+
+ .global main
+ .text
+main:
+ movl variable(%rip), %eax
+ ret
+ .data
+ptr:
+ .quad variable
+relocs:
+ .quad __RUNTIME_PSEUDO_RELOC_LIST__
+ .quad __RUNTIME_PSEUDO_RELOC_LIST_END__
diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test
index 6441bb2be30d..a10d6ed4d08d 100644
--- a/test/COFF/baserel.test
+++ b/test/COFF/baserel.test
@@ -47,9 +47,9 @@
# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck %s \
# RUN: --check-prefix=BASEREL-HEADER
#
-# RN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
-# RN: llvm-readobj -file-headers %t.exe | FileCheck %s \
-# RN: --check-prefix=NOBASEREL-HEADER
+# RUN: lld-link /out:%t.exe /entry:main /fixed %t.obj %p/Inputs/std64.lib
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s \
+# RUN: --check-prefix=NOBASEREL-HEADER
#
# BASEREL-HEADER-NOT: IMAGE_FILE_RELOCS_STRIPPED
#
diff --git a/test/COFF/broken-arm-reloc.yaml b/test/COFF/broken-arm-reloc.yaml
new file mode 100644
index 000000000000..ad4328bcb142
--- /dev/null
+++ b/test/COFF/broken-arm-reloc.yaml
@@ -0,0 +1,92 @@
+# REQUIRES: arm
+
+# .global main
+# .global variable
+# .text
+# .thumb
+#main:
+# movw r0, :lower16:variable
+# nop
+# movt r0, :upper16:variable
+# ldr r0, [r0]
+# bx lr
+# .data
+#variable:
+# .long 42
+
+# RUN: yaml2obj %s > %t.obj
+# RUN: not lld-link -out:%t.exe -entry:main %t.obj 2>&1 | FileCheck %s
+
+# CHECK: error: unexpected instruction in MOVT instruction in MOV32T relocation
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 40F2000000BFC0F2000000687047
+ Relocations:
+ - VirtualAddress: 0
+ SymbolName: variable
+ Type: IMAGE_REL_ARM_MOV32T
+ - Name: .data
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: 2A000000
+ - Name: .bss
+ Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+ Alignment: 4
+ SectionData: ''
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 14
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 2762100735
+ 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: 4
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 3482275674
+ 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: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: variable
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/comdat-jumptable.s b/test/COFF/comdat-jumptable.s
new file mode 100644
index 000000000000..31a7c5f6bcdf
--- /dev/null
+++ b/test/COFF/comdat-jumptable.s
@@ -0,0 +1,70 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t1.obj
+# RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/comdat-jumptable2.s -filetype=obj -o %t2.obj
+
+# RUN: llvm-objdump -s %t1.obj | FileCheck --check-prefix=OBJ1 %s
+# RUN: llvm-objdump -s %t2.obj | FileCheck --check-prefix=OBJ2 %s
+
+# RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.exe
+# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=EXE %s
+
+# Test linking cases where comdat functions have an associated jump table
+# in a non-comdat rdata (which GCC produces for functions with jump tables).
+# In these cases, ld.bfd keeps all rdata sections, but the relocations that
+# refer to discarded comdat sections just are emitted as they were originally.
+
+# In real scenarios, the jump table .rdata section should be identical across
+# all object files; here it is different to illustrate more clearly what
+# the linker actually does.
+
+# OBJ1: Contents of section .rdata:
+# OBJ1: 0000 aaaaaaaa 14000000 1e000000 28000000
+# OBJ1: 0010 bbbbbbbb
+
+# OBJ2: Contents of section .rdata:
+# OBJ2: 0000 cccccccc 14000000 1e000000 28000000
+# OBJ2: 0010 dddddddd
+
+# EXE: Contents of section .rdata:
+# EXE: 140002000 aaaaaaaa 0c100000 12100000 18100000
+# EXE: 140002010 bbbbbbbb cccccccc 14000000 1e000000
+# EXE: 140002020 28000000 dddddddd
+
+
+ .section .text@comdatfunc, "x"
+ .linkonce discard
+ .globl comdatfunc
+comdatfunc:
+ leaq .Ljumptable(%rip), %rax
+ movslq (%rax, %rcx, 4), %rcx
+ addq %rcx, %rax
+ jmp *%rax
+
+ .section .rdata, "dr"
+ .long 0xaaaaaaaa
+.Ljumptable:
+ .long .Ltail1-.Ljumptable
+ .long .Ltail2-.Ljumptable
+ .long .Ltail3-.Ljumptable
+ .long 0xbbbbbbbb
+
+ .section .text@comdatfunc, "x"
+# If assembled with binutils, the following line can be kept in:
+# .linkonce discard
+.Ltail1:
+ movl $1, %eax
+ ret
+.Ltail2:
+ movl $2, %eax
+ ret
+.Ltail3:
+ movl $3, %eax
+ ret
+
+
+ .text
+ .globl main
+main:
+ call comdatfunc
+ call otherfunc
+ ret
diff --git a/test/COFF/comdat-weak.test b/test/COFF/comdat-weak.test
new file mode 100644
index 000000000000..a2b4688bc4f4
--- /dev/null
+++ b/test/COFF/comdat-weak.test
@@ -0,0 +1,82 @@
+RUN: lld-link -lldmingw %S/Inputs/inline-weak.o %S/Inputs/inline-weak2.o -out:%t.exe
+
+When compiling certain forms of templated inline functions, some
+versions of GCC (tested with 5.4) produces a weak symbol for the function.
+Newer versions of GCC don't do this though.
+
+The bundled object files are an example of that, they can be produced
+with test code like this:
+
+$ cat inline-weak.h
+class MyClass {
+public:
+ template<typename... _Args> int get(_Args&&... args) {
+ return a;
+ }
+private:
+ int a;
+};
+
+$ cat inline-weak.cpp
+#include "inline-weak.h"
+
+int get(MyClass& a);
+
+int main(int argc, char* argv[]) {
+ MyClass a;
+ int ret = a.get();
+ ret += get(a);
+ return ret;
+}
+extern "C" void mainCRTStartup(void) {
+ main(0, (char**)0);
+}
+extern "C" void __main(void) {
+}
+
+$ cat inline-weak2.cpp
+#include "inline-weak.h"
+
+int get(MyClass& a) {
+ return a.get();
+}
+
+$ x86_64-w64-mingw32-g++ -std=c++11 -c inline-weak.cpp
+$ x86_64-w64-mingw32-g++ -std=c++11 -c inline-weak2.cpp
+
+$ x86_64-w64-mingw32-nm inline-weak.o | grep MyClass3get
+0000000000000000 p .pdata$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 t .text$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 T .weak._ZN7MyClass3getIIEEEiDpOT_.main
+0000000000000000 r .xdata$_ZN7MyClass3getIJEEEiDpOT_
+ w _ZN7MyClass3getIIEEEiDpOT_
+0000000000000000 T _ZN7MyClass3getIJEEEiDpOT_
+
+$ x86_64-w64-mingw32-nm inline-weak2.o | grep MyClass3get
+0000000000000000 p .pdata$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 t .text$_ZN7MyClass3getIJEEEiDpOT_
+0000000000000000 T .weak._ZN7MyClass3getIIEEEiDpOT_._Z3getR7MyClass
+0000000000000000 r .xdata$_ZN7MyClass3getIJEEEiDpOT_
+ w _ZN7MyClass3getIIEEEiDpOT_
+0000000000000000 T _ZN7MyClass3getIJEEEiDpOT_
+
+This can't be reproduced by assembling .s files with llvm-mc, since that
+always produces a symbol named .weak.<weaksymbol>.default, therefore
+the test uses prebuilt object files instead.
+
+In these cases, the undefined weak symbol points to the regular symbol
+.weak._ZN7MyClass3getIIEEEiDpOT_.<othersymbol>, where <othersymbol>
+varies among the object files that emit the same function. This regular
+symbol points to the same location as the comdat function
+_ZN7MyClass3getIJEEEiDpOT_.
+
+When linking, the comdat section from the second object file gets
+discarded, as it matches the one that already exists. This means that
+the uniquely named symbol .weak.<weakname>.<othername> points to a
+discarded section chunk.
+
+Previously, this would have triggered adding an Undefined symbol for
+this case, which would later break linking. However, also previously,
+if the second object file is linked in via a static library, this
+leftover symbol is retained as a Lazy symbol, which would make the link
+succeed.
diff --git a/test/COFF/common-replacement.s b/test/COFF/common-replacement.s
new file mode 100644
index 000000000000..115ebe5bfd11
--- /dev/null
+++ b/test/COFF/common-replacement.s
@@ -0,0 +1,35 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t1.obj
+# RUN: llvm-mc -triple=x86_64-windows-gnu %S/Inputs/common-replacement.s -filetype=obj -o %t2.obj
+
+# RUN: lld-link -lldmingw -entry:main %t1.obj %t2.obj -out:%t.exe -verbose 2>&1 \
+# RUN: | FileCheck -check-prefix VERBOSE %s
+# RUN: llvm-readobj -s %t.exe | FileCheck -check-prefix SECTIONS %s
+
+# VERBOSE: -aligncomm:"foo",2
+
+# As long as the .comm symbol is replaced with actual data, RawDataSize
+# below should be nonzero.
+
+# SECTIONS: Name: .data (2E 64 61 74 61 00 00 00)
+# SECTIONS-NEXT: VirtualSize: 0x8
+# SECTIONS-NEXT: VirtualAddress: 0x3000
+# SECTIONS-NEXT: RawDataSize: 512
+
+
+ .text
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl main
+ .p2align 4, 0x90
+main:
+ movl foo(%rip), %eax
+ retq
+
+# This produces an aligncomm directive, but when linking in
+# Inputs/common-replacement.s, this symbol is replaced by a normal defined
+# symbol instead.
+ .comm foo, 4, 2
diff --git a/test/COFF/could-not-open.test b/test/COFF/could-not-open.test
new file mode 100644
index 000000000000..87f11c34e7d4
--- /dev/null
+++ b/test/COFF/could-not-open.test
@@ -0,0 +1,5 @@
+RUN: not lld-link 01 2>&1 | FileCheck %s
+
+CHECK: could not open 01
+CHECK-NOT: /machine is not specified
+CHECK-NOT: subsystem must be defined
diff --git a/test/COFF/crt-dyn-initializer-order.test b/test/COFF/crt-dyn-initializer-order.test
new file mode 100644
index 000000000000..963b0657793b
--- /dev/null
+++ b/test/COFF/crt-dyn-initializer-order.test
@@ -0,0 +1,100 @@
+# // a.cpp
+# #include <iostream>
+# #include <vector>
+#
+# template <int Magic> struct TemplatedObject {
+# static std::vector<TemplatedObject<Magic> *> Instances;
+# TemplatedObject() { Instances.push_back(this); }
+# };
+#
+# using Object = TemplatedObject<0>;
+# template <> std::vector<Object *> Object::Instances{};
+# Object idle{};
+#
+# int main() {
+# if (Object::Instances.size() == 0)
+# std::cout << "It's broken" << std::endl;
+# else
+# std::cout << "It works!" << std::endl;
+# return 0;
+# }
+# // using `clang-cl /c a.cpp | lld-link a.obj` works
+# // using `cl /c a.cpp | lld-link a.obj` fails without lld/COFF/Writer.cpp/Writer::sortSectionChunks()
+
+# RUN: yaml2obj %s > %t.obj
+# RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_1.yaml > %t1.obj
+# RUN: yaml2obj %S/Inputs/crt-dyn-initializer-order_2.yaml > %t2.obj
+
+# CHECK: Name: .CRT
+# CHECK: Characteristics [
+# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA
+# CHECK-NEXT: IMAGE_SCN_MEM_READ
+# CHECK-NEXT: ]
+# CHECK-NEXT: SectionData (
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t1.obj %t2.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE1
+# CASE1-NEXT: 01020304 55701011 1205
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj %t2.obj %t1.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE2
+# CASE2-NEXT: 01020304 10111255 7005
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t2.obj %t.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE3
+# CASE3-NEXT: 01557010 11120203 0405
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t1.obj %t.obj %t2.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE4
+# CASE4-NEXT: 01557002 03041011 1205
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t1.obj %t.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE5
+# CASE5-NEXT: 01101112 55700203 0405
+
+# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t2.obj %t.obj %t1.obj
+# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s --check-prefixes CHECK,CASE6
+# CASE6-NEXT: 01101112 02030455 7005
+
+# CHECK-NEXT: )
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.CRT$XCA'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 01
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 02
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_LNK_COMDAT ]
+ Alignment: 1
+ SectionData: 03
+ - Name: '.CRT$XCU'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 04
+ - Name: '.CRT$XCZ'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ SectionData: 05
+symbols:
+ - Name: '.CRT$XCU'
+ 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: 1
+ Number: 2
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+...
diff --git a/test/COFF/ctors_dtors_priority.s b/test/COFF/ctors_dtors_priority.s
index efa03543027b..d50877f5afc5 100644
--- a/test/COFF/ctors_dtors_priority.s
+++ b/test/COFF/ctors_dtors_priority.s
@@ -1,12 +1,17 @@
# REQUIRES: x86
# RUN: llvm-mc -triple=x86_64-windows-gnu -filetype=obj -o %t.obj %s
-# RUN: lld-link -entry:main %t.obj -out:%t.exe
+# RUN: lld-link -lldmingw -entry:main %t.obj -out:%t.exe
# RUN: llvm-objdump -s %t.exe | FileCheck %s
.globl main
main:
nop
+# Check that these symbols point at the right spots.
+.data
+ .quad __CTOR_LIST__
+ .quad __DTOR_LIST__
+
.section .ctors.00005, "w"
.quad 2
.section .ctors, "w"
@@ -15,16 +20,26 @@ main:
.quad 3
.section .dtors, "w"
- .quad 1
+ .quad 4
.section .dtors.00100, "w"
- .quad 3
+ .quad 6
.section .dtors.00005, "w"
- .quad 2
+ .quad 5
+
+# Also test that the .CRT section is merged into .rdata
-# CHECK: Contents of section .ctors:
-# CHECK-NEXT: 140002000 01000000 00000000 02000000 00000000
-# CHECK-NEXT: 140002010 03000000 00000000
+.section .CRT$XCA, "dw"
+ .quad 7
+ .quad 8
-# CHECK: Contents of section .dtors:
-# CHECK-NEXT: 140003000 01000000 00000000 02000000 00000000
-# CHECK-NEXT: 140003010 03000000 00000000
+# CHECK: Contents of section .rdata:
+# CHECK-NEXT: 140002000 07000000 00000000 08000000 00000000
+# CHECK-NEXT: 140002010 ffffffff ffffffff 01000000 00000000
+# CHECK-NEXT: 140002020 02000000 00000000 03000000 00000000
+# CHECK-NEXT: 140002030 00000000 00000000 ffffffff ffffffff
+# CHECK-NEXT: 140002040 04000000 00000000 05000000 00000000
+# CHECK-NEXT: 140002050 06000000 00000000 00000000 00000000
+# __CTOR_LIST__ pointing at 0x140002010 and
+# __DTOR_LIST__ pointing at 0x140002038.
+# CHECK-NEXT: Contents of section .data:
+# CHECK-NEXT: 140003000 10200040 01000000 38200040 01000000
diff --git a/test/COFF/debug-fastlink.test b/test/COFF/debug-fastlink.test
new file mode 100644
index 000000000000..10b414195da3
--- /dev/null
+++ b/test/COFF/debug-fastlink.test
@@ -0,0 +1,12 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+
+; If /DEBUG:FASTLINK is specified, /DEBUG:FULL is used instead
+# RUN: rm -f %t.pdb
+# RUN: lld-link /DEBUG /pdb:%t.pdb /DEBUG:FASTLINK /entry:main /nodefaultlib %t1.obj %t2.obj \
+# RUN: 2>&1 | FileCheck %s
+
+# CHECK: /debug:fastlink unsupported; using /debug:full
+
+# RUN: ls %t.pdb
+
diff --git a/test/COFF/debug-reloc.s b/test/COFF/debug-reloc.s
index 57ab9bf9cdbc..897f31a6b5ed 100644
--- a/test/COFF/debug-reloc.s
+++ b/test/COFF/debug-reloc.s
@@ -8,35 +8,35 @@
# 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: Number: 3
# 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: VirtualAddress: 0x3000
+# SECTIONS: Number: 4
# SECTIONS-NEXT: Name: .data (2E 64 61 74 61 00 00 00)
# SECTIONS-NEXT: VirtualSize: 0x8
-# SECTIONS-NEXT: VirtualAddress: 0x3000
+# SECTIONS-NEXT: VirtualAddress: 0x4000
# RELOCS: BaseReloc [
# RELOCS-NEXT: Entry {
# RELOCS-NEXT: Type: DIR64
-# RELOCS-NEXT: Address: 0x3000
+# RELOCS-NEXT: Address: 0x4000
# RELOCS-NEXT: }
# RELOCS-NEXT: Entry {
# RELOCS-NEXT: Type: ABSOLUTE
-# RELOCS-NEXT: Address: 0x3000
+# RELOCS-NEXT: Address: 0x4000
# RELOCS-NEXT: }
# RELOCS-NEXT: ]
-# HEADERS: DebugRVA: 0x2000
+# HEADERS: DebugRVA: 0x3000
# HEADERS: DebugSize: 0x1C
# DEBUG: DebugDirectory [
# DEBUG: DebugEntry {
# DEBUG: Type: CodeView (0x2)
# DEBUG: SizeOfData: 0x19
-# DEBUG: AddressOfRawData: 0x201C
-# DEBUG: PointerToRawData: 0x61C
+# DEBUG: AddressOfRawData: 0x301C
+# DEBUG: PointerToRawData: 0x81C
.text
.def mainfunc;
diff --git a/test/COFF/directives.s b/test/COFF/directives.s
new file mode 100644
index 000000000000..9c4b7efd1dc9
--- /dev/null
+++ b/test/COFF/directives.s
@@ -0,0 +1,46 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -triple=x86_64-windows %s -filetype=obj -o %t.obj
+
+# RUN: lld-link -dll -out:%t.dll -entry:entry %t.obj -subsystem:console
+# RUN: llvm-objdump -p %t.dll | FileCheck %s
+
+# CHECK: Export Table:
+# CHECK: DLL name: directives.s.tmp.dll
+# CHECK: Ordinal RVA Name
+# CHECK-NEXT: 0 0
+# CHECK-NEXT: 1 0x1000 exportfn1
+# CHECK-NEXT: 2 0x1000 exportfn2
+# CHECK-NEXT: 3 0x1000 exportfn3
+# CHECK-NEXT: 4 0x1000 exportfn4
+# CHECK-NEXT: 5 0x1000 exportfn5
+# CHECK-NEXT: 6 0x1000 exportfn6
+
+ .global entry
+ .global exportfn1
+ .global exportfn2
+ .global exportfn3
+ .global exportfn4
+ .global exportfn5
+ .global exportfn6
+ .text
+entry:
+exportfn1:
+exportfn2:
+exportfn3:
+exportfn4:
+exportfn5:
+exportfn6:
+ ret
+ .section .drectve
+# Test that directive strings can be separated by any combination of
+# spaces and null bytes.
+ .ascii "-export:exportfn1 "
+ .asciz "-export:exportfn2"
+ .asciz "-export:exportfn3"
+ .asciz "-export:exportfn4 "
+ .byte 0
+ .ascii " "
+ .byte 0
+ .asciz "-export:exportfn5"
+ .asciz " -export:exportfn6"
diff --git a/test/COFF/duplicate-imp-func.s b/test/COFF/duplicate-imp-func.s
new file mode 100644
index 000000000000..fc0cf1ef6ae0
--- /dev/null
+++ b/test/COFF/duplicate-imp-func.s
@@ -0,0 +1,43 @@
+# REQUIRES: x86
+
+# RUN: echo -e ".globl libfunc\n.text\nlibfunc:\nret" > %t.lib.s
+# RUN: llvm-mc -triple=x86_64-windows-gnu %t.lib.s -filetype=obj -o %t.lib.o
+# RUN: lld-link -lldmingw -dll -out:%t.lib.dll -entry:libfunc %t.lib.o -implib:%t.lib.dll.a
+
+# RUN: echo -e ".globl helper1\n.text\nhelper1:\ncall libfunc\nret" > %t.helper1.s
+# RUN: echo -e ".globl helper2\n.text\nhelper2:\nret\n.globl libfunc\n.globl __imp_libfunc\nlibfunc:\nret\n.data\n__imp_libfunc:\n.quad libfunc" > %t.helper2.s
+# RUN: llvm-mc -triple=x86_64-windows-gnu %t.helper1.s -filetype=obj -o %t.helper1.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %t.helper2.s -filetype=obj -o %t.helper2.o
+
+# RUN: llvm-ar rcs %t.helper.a %t.helper1.o %t.helper2.o
+
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.main.o
+
+# Simulate a setup, where two libraries provide the same import function;
+# %t.lib.dll.a is a pure import library which provides "libfunc".
+# %t.helper.a is a static library which contains "helper1" and "helper2".
+#
+# helper1 contains an undefined reference to libfunc. helper2 contains a
+# fake local implementation of libfunc, together with the __imp_libfunc
+# stub.
+#
+# %t.lib.dll.a is listed before %t.helper.a on the command line. After
+# including helper1, the library member that first declared the Lazy libfunc
+# (%t.lib.dll.a) gets enqueued to be loaded. Before that gets done, helper2
+# gets loaded, which also turns out to provide a definition of libfunc.
+# Once the import library member from %t.lib.dll.a gets loaded, libfunc
+# and __imp_libfunc already are defined.
+
+# Just check that this fails cleanly (doesn't crash).
+# RUN: not lld-link -lldmingw -out:%t.main.exe -entry:main %t.main.o %t.lib.dll.a %t.helper.a
+
+# Test with %t.helper.a on the command line; in this case we won't try to
+# include libfunc from %t.lib.dll.a and everything works fine.
+# RUN: lld-link -lldmingw -out:%t.main.exe -entry:main %t.main.o %t.helper.a %t.lib.dll.a
+
+ .globl main
+ .text
+main:
+ call helper1
+ call helper2
+ ret
diff --git a/test/COFF/entry-inference-mingw.s b/test/COFF/entry-inference-mingw.s
new file mode 100644
index 000000000000..cf356205eb22
--- /dev/null
+++ b/test/COFF/entry-inference-mingw.s
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: lld-link -lldmingw %t.o -out:%t-default.exe 2>&1 | FileCheck -allow-empty -check-prefix=LINK %s
+# RUN: lld-link -lldmingw %t.o -out:%t-cui.exe -subsystem:console 2>&1 | FileCheck -allow-empty -check-prefix=LINK %s
+# RUN: lld-link -lldmingw %t.o -out:%t-gui.exe -subsystem:windows 2>&1 | FileCheck -allow-empty -check-prefix=LINK %s
+
+# RUN: llvm-readobj -file-headers %t-default.exe | FileCheck -check-prefix=CUI %s
+# RUN: llvm-readobj -file-headers %t-cui.exe | FileCheck -check-prefix=CUI %s
+# RUN: llvm-readobj -file-headers %t-gui.exe | FileCheck -check-prefix=GUI %s
+
+# Check that this doesn't print any warnings.
+# LINK-NOT: found both wmain and main
+
+# CUI: AddressOfEntryPoint: 0x1001
+# CUI: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+
+# GUI: AddressOfEntryPoint: 0x1002
+# GUI: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI (0x2)
+
+
+ .text
+ .globl mainCRTStartup
+ .globl WinMainCRTStartup
+# MinGW only uses the entry points above, these other ones aren't
+# used as entry.
+ .globl main
+ .globl wmain
+ .globl wmainCRTStartup
+ .globl wWinMainCRTStartup
+foo:
+ ret
+mainCRTStartup:
+ ret
+WinMainCRTStartup:
+ ret
+main:
+ ret
+wmain:
+ ret
+wmainCRTStartup:
+ ret
+wWinMainCRTStartup:
+ ret
diff --git a/test/COFF/entry-inference.test b/test/COFF/entry-inference.test
index 294870bf4185..b58a23a30e80 100644
--- a/test/COFF/entry-inference.test
+++ b/test/COFF/entry-inference.test
@@ -1,18 +1,26 @@
# RUN: sed -e s/ENTRYNAME/main/ %s | yaml2obj > %t.obj
# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
# RUN: sed s/ENTRYNAME/wmain/ %s | yaml2obj > %t.obj
# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
# RUN: sed s/ENTRYNAME/WinMain/ %s | yaml2obj > %t.obj
# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
# RUN: sed s/ENTRYNAME/wWinMain/ %s | yaml2obj > %t.obj
# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+# RUN: not lld-link /nodefaultlib /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
# MAIN: error: <root>: undefined symbol: mainCRTStartup
# WMAIN: error: <root>: undefined symbol: wmainCRTStartup
diff --git a/test/COFF/entry-inference3.test b/test/COFF/entry-inference3.test
index 7de14e10fe8d..53550f75c6c4 100644
--- a/test/COFF/entry-inference3.test
+++ b/test/COFF/entry-inference3.test
@@ -1,5 +1,9 @@
-# RUN: yaml2obj < %s > %t.obj
-# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: sed -e s/ENTRYNAME/mainCRTStartup/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
# RUN: FileCheck %s < %t.log
# CHECK: Entry name inferred: mainCRTStartup
@@ -26,7 +30,7 @@ symbols:
NumberOfLinenumbers: 0
CheckSum: 0
Number: 0
- - Name: mainCRTStartup
+ - Name: "ENTRYNAME"
Value: 0
SectionNumber: 1
SimpleType: IMAGE_SYM_TYPE_NULL
diff --git a/test/COFF/entry-inference332.test b/test/COFF/entry-inference332.test
new file mode 100644
index 000000000000..75c557af47e8
--- /dev/null
+++ b/test/COFF/entry-inference332.test
@@ -0,0 +1,39 @@
+# RUN: sed -e s/ENTRYNAME/_mainCRTStartup/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1
+# RUN: FileCheck %s < %t.log
+
+# RUN: sed -e s/ENTRYNAME/?mainCRTStartup@@YAHXZ/ %s | yaml2obj > %t.obj
+# RUN: lld-link /subsystem:console /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_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: "ENTRYNAME"
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/entry-inference4.test b/test/COFF/entry-inference4.test
new file mode 100644
index 000000000000..6b6a581f6c9d
--- /dev/null
+++ b/test/COFF/entry-inference4.test
@@ -0,0 +1,68 @@
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/wWinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:windows /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WWINMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/WinMain/;s/ENTRY2/wmain/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /subsystem:console /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/wmain/;s/ENTRY2/main/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=MAINWMAIN %s < %t.log
+
+# RUN: sed 's/ENTRY1/wWinMain/;s/ENTRY2/WinMain/' %s | yaml2obj > %t.obj
+# RUN: not lld-link /out:%t.exe %t.obj > %t.log 2>&1
+# RUN: FileCheck -check-prefix=WINMAINWWINMAIN %s < %t.log
+
+# MAIN: error: <root>: undefined symbol: mainCRTStartup
+# WMAIN: error: <root>: undefined symbol: wmainCRTStartup
+# MAINWMAIN: warning: found both wmain and main; using latter
+# MAINWMAIN: error: <root>: undefined symbol: mainCRTStartup
+# WINMAIN: error: <root>: undefined symbol: WinMainCRTStartup
+# WWINMAIN: error: <root>: undefined symbol: wWinMainCRTStartup
+# WINMAINWWINMAIN: warning: found both wWinMain and WinMain; using latter
+# WINMAINWWINMAIN: error: <root>: undefined symbol: WinMainCRTStartup
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+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: ENTRY1
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: ENTRY2
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/export-all.s b/test/COFF/export-all.s
index 5509a8dbac91..3d80603e2e71 100644
--- a/test/COFF/export-all.s
+++ b/test/COFF/export-all.s
@@ -3,14 +3,13 @@
# RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj
# RUN: lld-link -lldmingw -dll -out:%t.dll -entry:DllMainCRTStartup@12 %t.obj -implib:%t.lib
-# RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s
+# RUN: llvm-readobj -coff-exports %t.dll | grep Name: | FileCheck %s
# RUN: llvm-readobj %t.lib | FileCheck -check-prefix=IMPLIB %s
-# CHECK-NOT: Name: DllMainCRTStartup
-# CHECK-NOT: Name: _imp__unexported
-# CHECK: Name: dataSym
-# CHECK: Name: foobar
-# CHECK-NOT: Name: unexported
+# CHECK: Name:
+# CHECK-NEXT: Name: dataSym
+# CHECK-NEXT: Name: foobar
+# CHECK-EMPTY:
# IMPLIB: Symbol: __imp__dataSym
# IMPLIB-NOT: Symbol: _dataSym
@@ -22,6 +21,7 @@
.global _dataSym
.global _unexported
.global __imp__unexported
+.global .refptr._foobar
.text
_DllMainCRTStartup@12:
ret
@@ -34,6 +34,8 @@ _dataSym:
.int 4
__imp__unexported:
.int _unexported
+.refptr._foobar:
+ .int _foobar
# Test specifying -export-all-symbols, on an object file that contains
# dllexport directive for some of the symbols.
@@ -63,6 +65,7 @@ __imp__unexported:
# RUN: mkdir -p %T/libs
# RUN: echo -e ".global mingwfunc\n.text\nmingwfunc:\nret\n" > %T/libs/mingwfunc.s
# RUN: llvm-mc -triple=x86_64-windows-gnu %T/libs/mingwfunc.s -filetype=obj -o %T/libs/mingwfunc.o
+# RUN: rm -f %T/libs/libmingwex.a
# RUN: llvm-ar rcs %T/libs/libmingwex.a %T/libs/mingwfunc.o
# RUN: echo -e ".global crtfunc\n.text\ncrtfunc:\nret\n" > %T/libs/crtfunc.s
# RUN: llvm-mc -triple=x86_64-windows-gnu %T/libs/crtfunc.s -filetype=obj -o %T/libs/crt2.o
@@ -74,6 +77,18 @@ __imp__unexported:
# CHECK-EXCLUDE-NEXT: foobar @1
# CHECK-EXCLUDE-NEXT: EOF
+# Test that libraries included with -wholearchive: are autoexported, even if
+# they are in a library that otherwise normally would be excluded.
+
+# RUN: lld-link -out:%t.dll -dll -entry:DllMainCRTStartup %t.main.obj -lldmingw %T/libs/crt2.o -wholearchive:%T/libs/libmingwex.a -output-def:%t.def
+# RUN: echo "EOF" >> %t.def
+# RUN: cat %t.def | FileCheck -check-prefix=CHECK-WHOLEARCHIVE %s
+
+# CHECK-WHOLEARCHIVE: EXPORTS
+# CHECK-WHOLEARCHIVE-NEXT: foobar @1
+# CHECK-WHOLEARCHIVE-NEXT: mingwfunc @2
+# CHECK-WHOLEARCHIVE-NEXT: EOF
+
# Test that we handle import libraries together with -opt:noref.
# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj
diff --git a/test/COFF/export.test b/test/COFF/export.test
index a00a29c13d4c..8bf8c44c81dc 100644
--- a/test/COFF/export.test
+++ b/test/COFF/export.test
@@ -97,3 +97,12 @@ FORWARDER: Ordinal RVA Name
FORWARDER: 0 0
FORWARDER: 1 0x1010 exportfn
FORWARDER: 2 foo (forwarded to kernel32.foobar)
+
+# RUN: lld-link /out:%t.dll /dll %t.obj /merge:.rdata=.text /export:exportfn1 /export:exportfn2
+# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=MERGE -match-full-lines %s
+
+MERGE: DLL name: export.test.tmp.dll
+MERGE: Ordinal RVA Name
+MERGE-NEXT: 0 0
+MERGE-NEXT: 1 0x1008 exportfn1
+MERGE-NEXT: 2 0x1010 exportfn2
diff --git a/test/COFF/force-multiple.test b/test/COFF/force-multiple.test
new file mode 100644
index 000000000000..9f60e1394a3e
--- /dev/null
+++ b/test/COFF/force-multiple.test
@@ -0,0 +1,45 @@
+# RUN: yaml2obj < %s > %t1.obj
+# RUN: yaml2obj < %s > %t2.obj
+
+# RUN: not lld-link /out:%t.exe /entry:main %t1.obj %t2.obj >& %t.log
+# RUN: FileCheck -check-prefix=ERROR %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.obj /force >& %t.log
+# RUN: FileCheck -check-prefix=WARN %s < %t.log
+
+# RUN: lld-link /out:%t.exe /entry:main %t1.obj %t2.obj /force:multiple >& %t.log
+# RUN: FileCheck -check-prefix=WARN %s < %t.log
+
+# ERROR: error: duplicate symbol: main
+
+# WARN: warning: duplicate symbol: main
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 000000000000
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/gfids-export.s b/test/COFF/gfids-export.s
new file mode 100644
index 000000000000..87a4f4b47fa3
--- /dev/null
+++ b/test/COFF/gfids-export.s
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-pc-win32 %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -dll -out:%t.dll -noentry
+# RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s --check-prefix=CHECK
+
+# There should be a single entry in the table for the exported symbol.
+#
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x180001000
+# CHECK-NEXT: ]
+
+ .def func_export; .scl 2; .type 32; .endef
+ .globl func_export
+ .section .text,"xr",one_only,func_export
+ .p2align 4
+func_export:
+ movl $1, %eax
+ .globl label_export
+label_export:
+ movl $2, %eax
+ ret
+
+ .data
+ .globl data_export
+data_export:
+ .long 42
+
+ .section .drectve,"dr"
+ .ascii " /EXPORT:func_export"
+ .ascii " /EXPORT:label_export"
+ .ascii " /EXPORT:data_export"
+
+
+# Load configuration directory entry (winnt.h _IMAGE_LOAD_CONFIG_DIRECTORY64).
+# The linker will define the __guard_* symbols.
+ .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-relocations32.s b/test/COFF/gfids-relocations32.s
new file mode 100644
index 000000000000..0f7efeb46078
--- /dev/null
+++ b/test/COFF/gfids-relocations32.s
@@ -0,0 +1,87 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple i686-pc-win32 %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK
+
+# Only f and _main should go in the table.
+# (use /lldmap:map.txt to check their addresses).
+#
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x401000
+# CHECK-NEXT: 0x401030
+# CHECK-NEXT: ]
+
+# The input was loosly based on studying this program:
+#
+# void foo() { return; }
+# void bar() { return; }
+# int main() {
+# foo();
+# void (*arr[])() = { &bar };
+# (*arr[0])();
+# return 0;
+# }
+# cl /c a.cc && dumpbin /disasm a.obj > a.txt &&
+# link a.obj /guard:cf /map:map.txt && dumpbin /loadconfig a.exe
+
+
+
+ .def f;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,f
+ .p2align 4
+f: movl $1, %eax
+ ret
+
+
+ .def g;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,g
+ .p2align 4
+g: movl $2, %eax
+ ret
+
+
+ .def label;
+ .scl 6; # StorageClass: Label
+ .type 0; # Type: Not a function.
+ .endef
+ .section .text,"xr",one_only,label
+ .p2align 4
+label: ret
+
+
+ .data
+ .globl fp
+ .p2align 4
+fp: .long f # DIR32 relocation to function
+ .long label # DIR32 relocation to label
+
+
+ .def _main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,_main
+ .globl _main
+ .p2align 4
+_main: call *fp # DIR32 relocation to data
+ call g # REL32 relocation to function
+ ret
+
+
+# Load configuration directory entry (winnt.h _IMAGE_LOAD_CONFIG_DIRECTORY32).
+# The linker will define the ___guard_* symbols.
+ .section .rdata,"dr"
+.globl __load_config_used
+__load_config_used:
+ .long 104 # Size.
+ .fill 76, 1, 0
+ .long ___guard_fids_table
+ .long ___guard_fids_count
+ .long ___guard_flags
+ .fill 12, 1, 0
diff --git a/test/COFF/gfids-relocations64.s b/test/COFF/gfids-relocations64.s
new file mode 100644
index 000000000000..ae2e687222d5
--- /dev/null
+++ b/test/COFF/gfids-relocations64.s
@@ -0,0 +1,76 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple x86_64-pc-win32 %s -filetype=obj -o %t.obj
+# RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main
+# RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK
+
+# f, g, and main go in the table.
+# Including g isn't strictly necessary since it's not an indirect call target,
+# however the linker can't know that because relative relocations are used both
+# for direct calls and for getting the absolute address of a function.
+# (use /lldmap:map.txt to check their addresses).
+#
+# CHECK: GuardFidTable [
+# CHECK-NEXT: 0x140001000
+# CHECK-NEXT: 0x140001010
+# CHECK-NEXT: 0x140001030
+# CHECK-NEXT: ]
+
+ .def f;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,f
+ .p2align 4
+f: movl $1, %eax
+ ret
+
+
+ .def g;
+ .scl 3;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,g
+ .p2align 4
+g: movl $2, %eax
+ ret
+
+
+ .def label;
+ .scl 6; # StorageClass: Label
+ .type 0; # Type: Not a function.
+ .endef
+ .section .text,"xr",one_only,label
+ .p2align 4
+label: ret
+
+
+ .data
+ .globl fp
+ .p2align 4
+fp: .quad f # DIR32 relocation to function
+ .quad label # DIR32 relocation to label
+
+
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .section .text,"xr",one_only,main
+ .globl main
+ .p2align 4
+main: call *fp # DIR32 relocation to data
+ call g # REL32 relocation to function
+ ret
+
+
+# Load configuration directory entry (winnt.h _IMAGE_LOAD_CONFIG_DIRECTORY64).
+# The linker will define the __guard_* symbols.
+ .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/gnu-weak.test b/test/COFF/gnu-weak.test
new file mode 100644
index 000000000000..20284d7f0243
--- /dev/null
+++ b/test/COFF/gnu-weak.test
@@ -0,0 +1,52 @@
+RUN: lld-link -lldmingw %S/Inputs/gnu-weak.o %S/Inputs/gnu-weak2.o -out:%t.exe
+
+GNU ld can handle several definitions of the same weak symbol, and
+unless there is a strong definition of it, it just picks the first
+weak definition encountered.
+
+For each of the weak definitions, GNU tools produce a regular symbol
+named .weak.<weaksymbol>.<othersymbol>, where the other symbol name is
+another symbol defined close by.
+
+This can't be reproduced by assembling with llvm-mc, as llvm-mc always
+produces similar regular symbols named .weak.<weaksymbol>.default.
+
+The bundled object files can be produced from test code that looks like
+this:
+
+$ cat gnu-weak.c
+void weakfunc(void) __attribute__((weak));
+void otherfunc(void);
+
+__attribute__((weak)) void weakfunc() {
+}
+
+int main(int argc, char* argv[]) {
+ otherfunc();
+ weakfunc();
+ return 0;
+}
+void mainCRTStartup(void) {
+ main(0, (char**)0);
+}
+void __main(void) {
+}
+
+$ cat gnu-weak2.c
+void weakfunc(void) __attribute__((weak));
+
+__attribute__((weak)) void weakfunc() {
+}
+
+void otherfunc(void) {
+}
+
+$ x86_64-w64-mingw32-gcc -c -O2 gnu-weak.c
+$ x86_64-w64-mingw32-gcc -c -O2 gnu-weak2.c
+
+$ x86_64-w64-mingw32-nm gnu-weak.o | grep weakfunc
+0000000000000000 T .weak.weakfunc.main
+ w weakfunc
+$ x86_64-w64-mingw32-nm gnu-weak2.o | grep weakfunc
+0000000000000000 T .weak.weakfunc.otherfunc
+ w weakfunc
diff --git a/test/COFF/guardcf-align.s b/test/COFF/guardcf-align.s
index a0caabc92b0d..449d3fcd2a74 100644
--- a/test/COFF/guardcf-align.s
+++ b/test/COFF/guardcf-align.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/COFF/header-size.s b/test/COFF/header-size.s
new file mode 100644
index 000000000000..3373cdea84f0
--- /dev/null
+++ b/test/COFF/header-size.s
@@ -0,0 +1,12 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj
+// RUN: lld-link -entry:main -subsystem:console %t.obj -out:%t.exe
+// RUN: llvm-readobj -sections %t.exe | FileCheck %s
+ .globl main
+main:
+ ret
+
+// Check that the first section data comes at 512 bytes in the file.
+// If the size allocated for headers would include size for section
+// headers which aren't written, PointerToRawData would be 0x400 instead.
+// CHECK: PointerToRawData: 0x200
diff --git a/test/COFF/icf-safe.s b/test/COFF/icf-safe.s
new file mode 100644
index 000000000000..d16f21f458fc
--- /dev/null
+++ b/test/COFF/icf-safe.s
@@ -0,0 +1,37 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-win32 %s -o %t1.obj
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-win32 %S/Inputs/icf-safe.s -o %t2.obj
+# RUN: lld-link /dll /noentry /out:%t.dll /verbose /opt:noref,icf %t1.obj %t2.obj 2>&1 | FileCheck %s
+# RUN: lld-link /dll /noentry /out:%t.dll /verbose /opt:noref,icf /export:g3 /export:g4 %t1.obj %t2.obj 2>&1 | FileCheck --check-prefix=EXPORT %s
+
+# CHECK-NOT: Selected
+# CHECK: Selected g3
+# CHECK-NEXT: Removed g4
+# CHECK-NOT: Removed
+# CHECK-NOT: Selected
+
+# EXPORT-NOT: Selected
+
+.section .rdata,"dr",one_only,g1
+.globl g1
+g1:
+.byte 1
+
+.section .rdata,"dr",one_only,g2
+.globl g2
+g2:
+.byte 1
+
+.section .rdata,"dr",one_only,g3
+.globl g3
+g3:
+.byte 2
+
+.section .rdata,"dr",one_only,g4
+.globl g4
+g4:
+.byte 2
+
+.addrsig
+.addrsig_sym g1
+.addrsig_sym g2
diff --git a/test/COFF/ignore-many.test b/test/COFF/ignore-many.test
new file mode 100644
index 000000000000..31398106c171
--- /dev/null
+++ b/test/COFF/ignore-many.test
@@ -0,0 +1,16 @@
+Tests /ignore with more than one argument.
+
+RUN: yaml2obj %S/ignore4217.yaml > %t1.obj
+RUN: yaml2obj %S/Inputs/pdb-type-server-missing-2.yaml > %t2.obj
+RUN: echo foo > %t3.order
+
+RUN: lld-link /entry:main /out:%t.exe %t1.obj %t2.obj /order:@%t3.order /debug 2>&1 | FileCheck -check-prefix=WARNINGS %s
+RUN: lld-link /entry:main /out:%t.exe %t1.obj %t2.obj /order:@%t3.order /debug /ignore:4217,4099,4037 2>&1 | FileCheck -allow-empty -check-prefix=SUPPRESSED %s
+
+WARNINGS: locally defined symbol imported
+WARNINGS: missing symbol: foo
+WARNINGS: warning: Cannot use debug info for
+
+SUPPRESSED-NOT: locally defined symbol imported
+SUPPRESSED-NOT: missing symbol: foo
+SUPPRESSED-NOT: warning: Cannot use debug info for
diff --git a/test/COFF/imports-gnu-autoexport.s b/test/COFF/imports-gnu-autoexport.s
new file mode 100644
index 000000000000..8c204e1c665a
--- /dev/null
+++ b/test/COFF/imports-gnu-autoexport.s
@@ -0,0 +1,25 @@
+# REQUIRES: x86
+#
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-head.s -filetype=obj -o %t-dabcdh.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-func.s -filetype=obj -o %t-dabcds00000.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-tail.s -filetype=obj -o %t-dabcdt.o
+# RUN: rm -f %t-implib.a
+# RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o
+# RUN: lld-link -lldmingw -dll -out:%t.dll -entry:main -subsystem:console \
+# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib %t-implib.a -include:func
+# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix=EXPORT %s
+
+# Check that only the single normal symbol was exported, none of the symbols
+# from the import library.
+
+EXPORT: Export {
+EXPORT-NEXT: Ordinal: 0
+EXPORT-NEXT: Name:
+EXPORT-NEXT: RVA: 0x0
+EXPORT-NEXT: }
+EXPORT-NEXT: Export {
+EXPORT-NEXT: Ordinal: 1
+EXPORT-NEXT: Name: main
+EXPORT-NEXT: RVA: 0x1010
+EXPORT-NEXT: }
+EXPORT-NEXT-EMPTY:
diff --git a/test/COFF/imports-gnu-only.s b/test/COFF/imports-gnu-only.s
new file mode 100644
index 000000000000..8483598ede97
--- /dev/null
+++ b/test/COFF/imports-gnu-only.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+#
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-head.s -filetype=obj -o %t-dabcdh.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-func.s -filetype=obj -o %t-dabcds00000.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-tail.s -filetype=obj -o %t-dabcdt.o
+# RUN: rm -f %t-implib.a
+# RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -out:%t.exe -entry:main -subsystem:console \
+# RUN: %t.obj %t-implib.a
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DATA %s
+
+ .text
+ .global main
+main:
+ call func
+ ret
+
+# Check that the linker inserted the null terminating import descriptor,
+# even if there were no normal import libraries, only gnu ones.
+
+# DATA: Contents of section .rdata:
+# First import descriptor
+# DATA: 140002000 28200000 00000000 00000000 53200000
+# Last word from first import descriptor, null terminator descriptor
+# DATA: 140002010 38200000 00000000 00000000 00000000
+# Null terminator descriptor and import lookup table.
+# DATA: 140002020 00000000 00000000 48200000 00000000
diff --git a/test/COFF/imports-gnu.test b/test/COFF/imports-gnu.test
new file mode 100644
index 000000000000..e56be2f446b7
--- /dev/null
+++ b/test/COFF/imports-gnu.test
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# Verify that the lld can link to GNU import libs.
+#
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-head.s -filetype=obj -o %t-dabcdh.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-func.s -filetype=obj -o %t-dabcds00000.o
+# RUN: llvm-mc -triple=x86_64-windows-gnu %p/Inputs/gnu-implib-tail.s -filetype=obj -o %t-dabcdt.o
+# RUN: rm -f %t-implib.a
+# RUN: llvm-ar rcs %t-implib.a %t-dabcdh.o %t-dabcds00000.o %t-dabcdt.o
+# Not linking with -lldmingw; one can link to GNU import libs even if not targeting MinGW.
+# RUN: lld-link -out:%t.exe -entry:main -subsystem:console \
+# RUN: %p/Inputs/hello64.obj %p/Inputs/std64.lib %t-implib.a -include:func
+# RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s
+
+# Check that import entries from both libraries show up.
+
+IMPORT: Import {
+IMPORT-NEXT: Name: foo.dll
+IMPORT-NEXT: ImportLookupTableRVA:
+IMPORT-NEXT: ImportAddressTableRVA:
+IMPORT-NEXT: Symbol: func (0)
+IMPORT-NEXT: }
+IMPORT-NEXT: Import {
+IMPORT-NEXT: Name: std64.dll
+IMPORT-NEXT: ImportLookupTableRVA:
+IMPORT-NEXT: ImportAddressTableRVA:
+IMPORT-NEXT: Symbol: ExitProcess (0)
+IMPORT-NEXT: Symbol: (50)
+IMPORT-NEXT: Symbol: MessageBoxA (1)
+IMPORT-NEXT: }
diff --git a/test/COFF/invalid-debug-type.test b/test/COFF/invalid-debug-type.test
index 10264180314d..0fa40b0312b5 100644
--- a/test/COFF/invalid-debug-type.test
+++ b/test/COFF/invalid-debug-type.test
@@ -1,5 +1,6 @@
# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
# RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
-# RUN: %t1.obj %t2.obj
+# RUN: %t1.obj %t2.obj 2>&1 | FileCheck %s
+# CHECK: /debugtype: unknown option: invalid \ No newline at end of file
diff --git a/test/COFF/invalid-debug.test b/test/COFF/invalid-debug.test
new file mode 100644
index 000000000000..67f794f8b1b3
--- /dev/null
+++ b/test/COFF/invalid-debug.test
@@ -0,0 +1,6 @@
+# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj
+# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj
+# RUN: not lld-link /debug /debug:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \
+# RUN: %t1.obj %t2.obj 2>&1 | FileCheck %s
+
+# CHECK: /debug: unknown option: invalid
diff --git a/test/COFF/libname-mingw.test b/test/COFF/libname-mingw.test
new file mode 100644
index 000000000000..171164f73461
--- /dev/null
+++ b/test/COFF/libname-mingw.test
@@ -0,0 +1,8 @@
+# RUN: mkdir -p %t/a
+# RUN: cp %p/Inputs/std64.lib %t/a/libstd64.a
+
+# RUN: lld-link /lldmingw /out:%t.exe /entry:main /verbose \
+# RUN: /defaultlib:std64.lib /subsystem:console %p/Inputs/hello64.obj \
+# RUN: /libpath:%t/a 2>&1 | FileCheck %s
+
+CHECK: a{{[/\\]}}libstd64.a
diff --git a/test/COFF/line-error.yaml b/test/COFF/line-error.yaml
new file mode 100644
index 000000000000..55fb723a6abb
--- /dev/null
+++ b/test/COFF/line-error.yaml
@@ -0,0 +1,160 @@
+# RUN: yaml2obj %s -o %t.obj
+# RUN: not lld-link %t.obj /subsystem:console 2>&1 | FileCheck %s
+
+# CHECK: lld-link: error: undefined symbol: function
+# CHECK-NEXT: >>> referenced by {{.*}}line-error.yaml.tmp.obj:(caller1)
+# CHECK-NEXT: >>> referenced by E:\file.cpp:1935
+# CHECK-NEXT: >>> {{.*}}line-error.yaml.tmp.obj:(caller22)
+
+--- !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: 488B0500000000488B51284881C2D80000004889C148FF2500000000
+ Relocations:
+ - VirtualAddress: 3
+ SymbolName: function
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 488B0500000000488B51084881C2D80000004889C148FF2500000000
+ Relocations:
+ - VirtualAddress: 3
+ SymbolName: function
+ Type: IMAGE_REL_AMD64_REL32
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Subsections:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'E:\file.cpp'
+ Kind: MD5
+ Checksum: D72EDEF8B8E50C364A330F9CB3CD904B
+ - !StringTable
+ Strings:
+ - 'E:\file.cpp'
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Subsections:
+ - !Lines
+ CodeSize: 28
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks: []
+ Relocations:
+ - VirtualAddress: 12
+ SymbolName: caller1
+ Type: IMAGE_REL_AMD64_SECREL
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Subsections:
+ - !Lines
+ CodeSize: 28
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'E:\file.cpp'
+ Lines:
+ - Offset: 11
+ LineStart: 1935
+ IsStatement: false
+ EndDelta: 0
+ Columns: []
+ Relocations:
+ - VirtualAddress: 12
+ SymbolName: caller22
+ Type: IMAGE_REL_AMD64_SECREL
+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: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 2430089736
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: caller1
+ 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: 28
+ NumberOfRelocations: 2
+ NumberOfLinenumbers: 0
+ CheckSum: 3449717304
+ Number: 2
+ Selection: IMAGE_COMDAT_SELECT_NODUPLICATES
+ - Name: caller22
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 767204
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 4280093374
+ Number: 3
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 4
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 296
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 1957793731
+ Number: 1
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 5
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 276
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 1957793731
+ Number: 2
+ Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE
+ - Name: function
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/lto-cache.ll b/test/COFF/lto-cache.ll
index ad1a3b71f19a..828f5e5a97c1 100644
--- a/test/COFF/lto-cache.ll
+++ b/test/COFF/lto-cache.ll
@@ -1,4 +1,6 @@
; REQUIRES: x86
+; NetBSD: noatime mounts currently inhibit 'touch' from updating atime
+; UNSUPPORTED: system-netbsd
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/lto-cache.ll -o %t2.o
diff --git a/test/COFF/lto-chkstk.ll b/test/COFF/lto-chkstk.ll
index cf831615ec52..1df93c6b9545 100644
--- a/test/COFF/lto-chkstk.ll
+++ b/test/COFF/lto-chkstk.ll
@@ -2,6 +2,7 @@
; RUN: llvm-as -o %t.obj %s
; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-foo.obj %S/Inputs/lto-chkstk-foo.s
; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-chkstk.obj %S/Inputs/lto-chkstk-chkstk.s
+; RUN: rm -f %t.lib
; RUN: llvm-ar cru %t.lib %T/lto-chkstk-chkstk.obj
; RUN: lld-link /out:%t.exe /entry:main /subsystem:console %t.obj %T/lto-chkstk-foo.obj %t.lib
diff --git a/test/COFF/lto-cpu-string.ll b/test/COFF/lto-cpu-string.ll
new file mode 100644
index 000000000000..840adcebf46d
--- /dev/null
+++ b/test/COFF/lto-cpu-string.ll
@@ -0,0 +1,21 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.obj
+
+; RUN: lld-link %t.obj -noentry -nodefaultlib -out:%t.dll -dll
+; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.dll | FileCheck %s
+; CHECK: nop{{$}}
+
+; RUN: lld-link -mllvm:-mcpu=znver1 -noentry -nodefaultlib %t.obj -out:%t.znver1.dll -dll
+; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.znver1.dll | FileCheck -check-prefix=ZNVER1 %s
+; ZNVER1: nopw
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc19.14.26433"
+
+define dllexport 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/COFF/msvclto-archive.ll b/test/COFF/msvclto-archive.ll
deleted file mode 100644
index f09532721024..000000000000
--- a/test/COFF/msvclto-archive.ll
+++ /dev/null
@@ -1,40 +0,0 @@
-; REQUIRES: x86
-;; Make sure we re-create archive files to strip bitcode files.
-
-;; Do not create empty archives because the MSVC linker
-;; doesn't support them.
-; RUN: llvm-as -o %t.obj %s
-; RUN: rm -f %t-main1.a
-; RUN: llvm-ar cru %t-main1.a %t.obj
-; RUN: mkdir -p %t.dir
-; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t.dir/bitcode.obj %p/Inputs/msvclto.s
-; RUN: lld-link %t-main1.a %t.dir/bitcode.obj /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
-; RUN: /entry:main /verbose 2> %t.log || true
-; RUN: FileCheck -check-prefix=BC %s < %t.log
-; BC-NOT: Creating a temporary archive for
-
-; RUN: rm -f %t-main2.a
-; RUN: llvm-ar cru %t-main2.a %t.dir/bitcode.obj
-; RUN: lld-link %t.obj %t-main2.a /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
-; RUN: /entry:main /verbose 2> %t.log || true
-; RUN: FileCheck -check-prefix=OBJ %s < %t.log
-; OBJ-NOT: Creating a temporary archive
-
-;; Make sure that we always rebuild thin archives because
-;; the MSVC linker doesn't support thin archives.
-; RUN: rm -f %t-main3.a
-; RUN: llvm-ar cruT %t-main3.a %t.dir/bitcode.obj
-; RUN: lld-link %t.obj %t-main3.a /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
-; RUN: /entry:main /verbose 2> %t.log || true
-; RUN: FileCheck -check-prefix=THIN %s < %t.log
-; THIN: Creating a temporary archive
-
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-pc-windows-msvc"
-
-declare void @foo()
-
-define i32 @main() {
- call void @foo()
- ret i32 0
-}
diff --git a/test/COFF/msvclto-order.ll b/test/COFF/msvclto-order.ll
deleted file mode 100644
index 1758077fe748..000000000000
--- a/test/COFF/msvclto-order.ll
+++ /dev/null
@@ -1,25 +0,0 @@
-; REQUIRES: x86
-; RUN: opt -thinlto-bc %s -o %t.obj
-; RUN: llc -filetype=obj %S/Inputs/msvclto-order-a.ll -o %T/msvclto-order-a.obj
-; RUN: llvm-ar crs %T/msvclto-order-a.lib %T/msvclto-order-a.obj
-; RUN: llc -filetype=obj %S/Inputs/msvclto-order-b.ll -o %T/msvclto-order-b.obj
-; RUN: llvm-ar crs %T/msvclto-order-b.lib %T/msvclto-order-b.obj
-; RUN: lld-link /verbose /msvclto /out:%t.exe /entry:main %t.obj \
-; RUN: %T/msvclto-order-a.lib %T/msvclto-order-b.lib 2> %t.log || true
-; RUN: FileCheck %s < %t.log
-
-; CHECK: : link.exe
-; CHECK-NOT: .lib{{$}}
-; CHECK: lld-msvclto-order-a{{.*}}.obj
-; CHECK-NOT: lld-msvclto-order-b{{.*}}.obj
-; CHECK: .lib{{$}}
-
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-pc-windows-msvc"
-
-declare void @foo()
-
-define i32 @main() {
- call void @foo()
- ret i32 0
-}
diff --git a/test/COFF/msvclto.ll b/test/COFF/msvclto.ll
deleted file mode 100644
index b29982737f14..000000000000
--- a/test/COFF/msvclto.ll
+++ /dev/null
@@ -1,20 +0,0 @@
-; REQUIRES: x86
-; RUN: llvm-as -o %t.obj %s
-; RUN: mkdir -p %t.dir
-; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %t.dir/bitcode.obj %p/Inputs/msvclto.s
-; RUN: lld-link %t.obj %t.dir/bitcode.obj /msvclto /out:%t.exe /opt:lldlto=1 /opt:icf \
-; RUN: /entry:main /verbose 2> %t.log || true
-; RUN: FileCheck %s < %t.log
-
-; CHECK: /opt:icf /entry:main
-; CHECK: /verbose
-
-target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-pc-windows-msvc"
-
-declare void @foo()
-
-define i32 @main() {
- call void @foo()
- ret i32 0
-}
diff --git a/test/COFF/no-idata.s b/test/COFF/no-idata.s
new file mode 100644
index 000000000000..d2f78d5598c7
--- /dev/null
+++ b/test/COFF/no-idata.s
@@ -0,0 +1,20 @@
+# REQUIRES: x86
+#
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj
+# RUN: lld-link -out:%t.exe -entry:main -subsystem:console %t.obj
+# RUN: llvm-objdump -s %t.exe | FileCheck -check-prefix=DUMP %s
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=DIRECTORY %s
+
+ .text
+ .global main
+main:
+ ret
+
+# Check that no .idata (.rdata) entries were added, no null terminator
+# for the import descriptor table.
+# DUMP: Contents of section .text:
+# DUMP-NEXT: 140001000 c3
+# DUMP-NEXT-EMPTY:
+
+# DIRECTORY: ImportTableRVA: 0x0
+# DIRECTORY: ImportTableSize: 0x0
diff --git a/test/COFF/pdb-debug-f.s b/test/COFF/pdb-debug-f.s
new file mode 100644
index 000000000000..624c1192914a
--- /dev/null
+++ b/test/COFF/pdb-debug-f.s
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=i386-pc-win32 -filetype=obj -o %t.obj %s
+# RUN: lld-link /subsystem:console /debug /nodefaultlib /entry:foo /out:%t.exe /pdb:%t.pdb %t.obj
+# RUN: llvm-pdbutil dump -fpo %t.pdb | FileCheck %s
+
+# CHECK: Old FPO Data
+# CHECK-NEXT: ============================================================
+# CHECK-NEXT: RVA | Code | Locals | Params | Prolog | Saved Regs | Use BP | Has SEH | Frame Type
+# CHECK-NEXT: 00001002 | 1 | 2 | 3 | 4 | 0 | false | false | FPO
+
+.text
+_foo:
+ret
+
+.global _foo
+
+.section .debug$F,"dr"
+ .long _foo@IMGREL+2
+ .long 1 # cbProc
+ .long 2 # cdwLocals;
+ .short 3 # cdwParams;
+ .short 4 # flags
+ # cbProlog : 8;
+ # cbRegs : 3;
+ # fHasSEH : 1;
+ # fUseBP : 1;
+ # reserved : 1;
+ # cbFrame : 2; \ No newline at end of file
diff --git a/test/COFF/pdb-framedata.yaml b/test/COFF/pdb-framedata.yaml
new file mode 100644
index 000000000000..fad042f392bb
--- /dev/null
+++ b/test/COFF/pdb-framedata.yaml
@@ -0,0 +1,462 @@
+# // Compile with clang-cl -m32 /Z7 /GS- /c t.obj pdb-framedata.cpp
+#
+# int func(int x, int y) {
+# return x + y;
+# }
+#
+# int main(int argc, char **argv) {
+# return func(argc, argc+1);
+# }
+
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj -debug -entry:main -nodefaultlib -debug -out:%t.exe -pdb:%t.pdb
+# RUN: llvm-pdbutil dump -fpo %t.pdb | FileCheck %s
+
+# CHECK: New FPO Data
+# CHECK-NEXT: ============================================================
+# CHECK-NEXT: RVA | Code | Locals | Params | Stack | Prolog | Saved Regs | Has SEH | Has C++EH | Start | Program
+# CHECK-NEXT: 00001000 | 31 | 0 | 8 | 0 | 6 | 0 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# CHECK-NEXT: 00001001 | 30 | 0 | 8 | 0 | 5 | 4 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# CHECK-NEXT: 00001003 | 28 | 0 | 8 | 0 | 3 | 4 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# CHECK-NEXT: 00001020 | 53 | 0 | 8 | 0 | 7 | 0 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + =
+# CHECK-NEXT: 00001021 | 52 | 0 | 8 | 0 | 6 | 4 | false | false | false | $T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# CHECK-NEXT: 00001023 | 50 | 0 | 8 | 0 | 4 | 4 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ =
+# CHECK-NEXT: 00001024 | 49 | 0 | 8 | 0 | 3 | 8 | false | false | false | $T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ =
+
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_I386
+ Characteristics: [ ]
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 5589E583EC088B450C8B4D088B550803550C8945FC89D0894DF883C4085DC3905589E55683EC148B450C8B4D08C745F8000000008B550883C2018B7508893424895424048945F4894DF0E80000000083C4145E5DC3
+ Relocations:
+ - VirtualAddress: 75
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_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: .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
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_COMPILE3
+ Compile3Sym:
+ Flags: [ ]
+ Machine: Pentium3
+ FrontendMajor: 8
+ FrontendMinor: 0
+ FrontendBuild: 0
+ FrontendQFE: 0
+ BackendMajor: 8000
+ BackendMinor: 0
+ BackendBuild: 0
+ BackendQFE: 0
+ Version: 'clang version 8.0.0 '
+ - !FrameData
+ Frames:
+ - CodeSize: 31
+ FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 6
+ RvaStart: 0
+ SavedRegsSize: 0
+ - CodeSize: 30
+ FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 5
+ RvaStart: 1
+ SavedRegsSize: 4
+ - CodeSize: 28
+ FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 3
+ RvaStart: 3
+ SavedRegsSize: 4
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 31
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4098
+ Flags: [ ]
+ DisplayName: func
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: x
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 12
+ ISectStart: 0
+ Range: 19
+ Gaps:
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: y
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 12
+ Range:
+ OffsetStart: 12
+ ISectStart: 0
+ Range: 19
+ Gaps:
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 31
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 3
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 12
+ LineStart: 4
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ - !FrameData
+ Frames:
+ - CodeSize: 53
+ FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 7
+ RvaStart: 0
+ SavedRegsSize: 0
+ - CodeSize: 52
+ FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 6
+ RvaStart: 1
+ SavedRegsSize: 4
+ - CodeSize: 50
+ FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 4
+ RvaStart: 3
+ SavedRegsSize: 4
+ - CodeSize: 49
+ FrameFunc: '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = '
+ LocalSize: 0
+ MaxStackSize: 0
+ ParamsSize: 8
+ PrologSize: 3
+ RvaStart: 4
+ SavedRegsSize: 8
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 53
+ DbgStart: 0
+ DbgEnd: 0
+ FunctionType: 4102
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 116
+ Flags: [ IsParameter ]
+ VarName: argc
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 8
+ Range:
+ OffsetStart: 52
+ ISectStart: 0
+ Range: 33
+ Gaps:
+ - Kind: S_LOCAL
+ LocalSym:
+ Type: 4099
+ Flags: [ IsParameter ]
+ VarName: argv
+ - Kind: S_DEFRANGE_REGISTER_REL
+ DefRangeRegisterRelSym:
+ Register: 22
+ Flags: 0
+ BasePointerOffset: 12
+ Range:
+ OffsetStart: 52
+ ISectStart: 0
+ Range: 33
+ Gaps:
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 53
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp'
+ Lines:
+ - Offset: 0
+ LineStart: 7
+ IsStatement: false
+ EndDelta: 0
+ - Offset: 20
+ LineStart: 8
+ IsStatement: false
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.cpp'
+ Kind: MD5
+ Checksum: A611B73E19B77B02646FAAF7CAEB025D
+ - !StringTable
+ Strings:
+ - 'D:\src\llvmbuild\cl\Debug\x64\pdb-framedata.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 - ^ = '
+ - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = '
+ - ''
+ Relocations:
+ - VirtualAddress: 68
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_DIR32NB
+ - VirtualAddress: 208
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 212
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 244
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 248
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 276
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 280
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 296
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 300
+ SymbolName: '?func@@YAHHH@Z'
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 344
+ SymbolName: _main
+ Type: IMAGE_REL_I386_DIR32NB
+ - VirtualAddress: 516
+ SymbolName: _main
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 520
+ SymbolName: _main
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 555
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 559
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 590
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 594
+ SymbolName: .text
+ Type: IMAGE_REL_I386_SECTION
+ - VirtualAddress: 612
+ SymbolName: _main
+ Type: IMAGE_REL_I386_SECREL
+ - VirtualAddress: 616
+ SymbolName: _main
+ Type: IMAGE_REL_I386_SECTION
+ - Name: '.debug$T'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ Types:
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116, 116 ]
+ - Kind: LF_PROCEDURE
+ Procedure:
+ ReturnType: 116
+ CallConv: NearC
+ Options: [ None ]
+ ParameterCount: 2
+ ArgumentList: 4096
+ - Kind: LF_FUNC_ID
+ FuncId:
+ ParentScope: 0
+ FunctionType: 4097
+ Name: func
+ - Kind: LF_POINTER
+ Pointer:
+ ReferentType: 1136
+ Attrs: 32778
+ - Kind: LF_ARGLIST
+ ArgList:
+ ArgIndices: [ 116, 4099 ]
+ - 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
+ - Name: .llvm_addrsig
+ Characteristics: [ IMAGE_SCN_LNK_REMOVE ]
+ Alignment: 1
+ SectionData: 0F
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 85
+ NumberOfRelocations: 1
+ NumberOfLinenumbers: 0
+ CheckSum: 1989857796
+ 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: 988
+ NumberOfRelocations: 18
+ NumberOfLinenumbers: 0
+ CheckSum: 2571438511
+ 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: 120
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 3148269371
+ Number: 6
+ - Name: .llvm_addrsig
+ Value: 0
+ SectionNumber: 7
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 1
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 2428444049
+ Number: 7
+ - Name: '@feat.00'
+ Value: 1
+ SectionNumber: -1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ - Name: '?func@@YAHHH@Z'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _main
+ Value: 32
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-global-hashes.test b/test/COFF/pdb-global-hashes.test
index 238613cef69c..0ca60057e704 100644
--- a/test/COFF/pdb-global-hashes.test
+++ b/test/COFF/pdb-global-hashes.test
@@ -4,9 +4,9 @@ RUN: yaml2obj %p/Inputs/pdb-hashes-2-missing.yaml > %t.2.missing.obj
RUN: lld-link /debug %t.1.obj %t.2.obj /entry:main /nodefaultlib /PDB:%t.nohash.pdb
RUN: lld-link /debug:ghash %t.1.obj %t.2.obj /entry:main /nodefaultlib /PDB:%t.hash.pdb
RUN: lld-link /debug:ghash %t.1.obj %t.2.missing.obj /entry:main /nodefaultlib /PDB:%t.mixed.pdb
-RUN: llvm-pdbutil dump -types -ids %t.nohash.pdb | FileCheck %s
-RUN: llvm-pdbutil dump -types -ids %t.hash.pdb | FileCheck %s
-RUN: llvm-pdbutil dump -types -ids %t.mixed.pdb | FileCheck %s
+RUN: llvm-pdbutil dump -types -ids -dont-resolve-forward-refs %t.nohash.pdb | FileCheck %s
+RUN: llvm-pdbutil dump -types -ids -dont-resolve-forward-refs %t.hash.pdb | FileCheck %s
+RUN: llvm-pdbutil dump -types -ids -dont-resolve-forward-refs %t.mixed.pdb | FileCheck %s
; These object files were generated via the following inputs and commands:
; ----------------------------------------------
diff --git a/test/COFF/pdb-globals.test b/test/COFF/pdb-globals.test
index db0d3f6d7e8d..ee9c0ef2efee 100644
--- a/test/COFF/pdb-globals.test
+++ b/test/COFF/pdb-globals.test
@@ -15,6 +15,8 @@ RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s
CHECK-LABEL: Global Symbols
CHECK-NEXT: ============================================================
CHECK-NEXT: Records
+CHECK-NEXT: 340 | S_UDT [size = 20] `HelloPoint`
+CHECK-NEXT: original type = 0x1007
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`
@@ -25,9 +27,11 @@ CHECK-NEXT: 232 | S_GDATA32 [size = 28] `__purecall`
CHECK-NEXT: type = 0x0403 (void*), addr = 0003:0004
CHECK-NEXT: 260 | S_GDATA32 [size = 24] `GlobalVar`
CHECK-NEXT: type = 0x100B (const int*), addr = 0003:0000
+CHECK-NEXT: 312 | S_UDT [size = 28] `HelloPointTypedef`
+CHECK-NEXT: original type = 0x1005
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: 360 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
CHECK-NEXT: module = 1, sum name = 0, offset = 376
CHECK-LABEL: Symbols
diff --git a/test/COFF/pdb-heapsite.yaml b/test/COFF/pdb-heapsite.yaml
index bfdd7b4dc555..966ae4284890 100644
--- a/test/COFF/pdb-heapsite.yaml
+++ b/test/COFF/pdb-heapsite.yaml
@@ -69,7 +69,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 35
- Register: CVRegRSP
+ Register: RSP
VarName: __formal
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test
index 022a447e4d55..48836a91fffb 100644
--- a/test/COFF/pdb-linker-module.test
+++ b/test/COFF/pdb-linker-module.test
@@ -1,11 +1,11 @@
RUN: echo "/nodefaultlib" > %t.rsp
-RUN: lld-link /debug /pdb:%t.pdb @%t.rsp /entry:main %S/Inputs/pdb-diff.obj
+RUN: lld-link /debug /pdb:%t.pdb @%t.rsp /entry:"1 "'"'hello'"'" 2" /manifestuac:"level='asInvoker' uiAccess='false'" %S/Inputs/pdb-diff.obj /force
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: 12, # files: 0, has ec info: false
+MODS-NEXT: debug stream: 13, # 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 *`
@@ -22,4 +22,4 @@ SYMS-NEXT: - {{.*}}lld-link
SYMS-NEXT: - pdb
SYMS-NEXT: - {{.*}}pdb-linker-module{{.*}}pdb
SYMS-NEXT: - cmd
-SYMS-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib /entry:main {{.*}}pdb-diff.obj
+SYMS-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib "/entry:1 ""hello"" 2" "/manifestuac:level='asInvoker' uiAccess='false'" {{.*}}pdb-diff.obj
diff --git a/test/COFF/pdb-options.test b/test/COFF/pdb-options.test
index 2bd1d920ee48..f0edc2f3bc79 100644
--- a/test/COFF/pdb-options.test
+++ b/test/COFF/pdb-options.test
@@ -6,6 +6,11 @@
# RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
# RUN: not ls %t.pdb
+; If /DEBUG:NONE is specified after /DEBUG, /pdb is ignored.
+# RUN: rm -f %t.pdb
+# RUN: lld-link /DEBUG /pdb:%t.pdb /DEBUG:NONE /entry:main /nodefaultlib %t1.obj %t2.obj
+# RUN: not ls %t.pdb
+
; If /DEBUG and /pdb are specified, it uses the specified name.
# RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj
# RUN: ls %t.pdb
diff --git a/test/COFF/pdb-procid-remapping.test b/test/COFF/pdb-procid-remapping.test
index e42616dae47d..d9b4faa8c0a9 100644
--- a/test/COFF/pdb-procid-remapping.test
+++ b/test/COFF/pdb-procid-remapping.test
@@ -14,6 +14,7 @@ CHECK-NEXT: type = `0x1004 (int (<no type>))`, debug start = 4, d
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0
CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK-NEXT: local fp reg = NONE, param fp reg = NONE
CHECK-NEXT: flags = has async eh | opt speed
CHECK-NEXT: 168 | S_END [size = 4]
CHECK-LABEL: Mod 0001 |
@@ -23,6 +24,7 @@ CHECK-NEXT: type = `0x1001 (int ())`, debug start = 0, debug end
CHECK-NEXT: 136 | S_FRAMEPROC [size = 32]
CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0
CHECK-NEXT: bytes of callee saved registers = 0, exception handler addr = 0000:0000
+CHECK-NEXT: local fp reg = NONE, param fp reg = NONE
CHECK-NEXT: flags = has async eh | opt speed
CHECK-NEXT: 168 | S_END [size = 4]
CHECK-LABEL: Mod 0002 |
diff --git a/test/COFF/pdb-relative-source-lines.test b/test/COFF/pdb-relative-source-lines.test
index 8c0894c21801..865d7a6d8a0a 100644
--- a/test/COFF/pdb-relative-source-lines.test
+++ b/test/COFF/pdb-relative-source-lines.test
@@ -17,29 +17,89 @@ 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
+/pdbsourcepath: only sets the directory that relative paths are considered
+relative to, so this test needs to pass relative paths to lld-link for:
+1. The input obj files
+2. The /pdb: switch
+3. The lld-link invocation itself
+To achieve this, put all inputs of the lld-link invocation (including lld-link
+itself) in a temp directory that's cwd and then make sure to only use relative
+arguments when calling ./lld-link below.
+RUN: rm -rf %t
+RUN: mkdir %t
+RUN: cp lld-link %t/lld-link
+RUN: cd %t
+
+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: ./lld-link -debug "-pdbsourcepath:c:\src" -entry:main -nodefaultlib -out:out.exe -pdb:out.pdb pdb_lines_1_relative.obj pdb_lines_2_relative.obj
+RUN: llvm-pdbutil pdb2yaml -modules -module-files -module-syms -subsections=lines,fc %t/out.pdb | FileCheck %s
+RUN: ./lld-link -debug "-pdbsourcepath:/usr/src" -entry:main -nodefaultlib -out:out.exe -pdb:out.pdb pdb_lines_1_relative.obj pdb_lines_2_relative.obj
+RUN: llvm-pdbutil pdb2yaml -modules -module-files -module-syms -subsections=lines,fc %t/out.pdb | FileCheck --check-prefix=POSIX %s
+
+CHECK-LABEL: - Module: 'c:\src{{[\\/]}}pdb_lines_1_relative.obj'
+CHECK-NEXT: ObjFile: 'c:\src{{[\\/]}}pdb_lines_1_relative.obj'
CHECK: SourceFiles:
-CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c'
-CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}foo.h'
+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: - 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: - 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-LABEL: - Module: 'c:\src{{[\\/]}}pdb_lines_2_relative.obj'
+CHECK-NEXT: ObjFile: 'c:\src{{[\\/]}}pdb_lines_2_relative.obj'
CHECK: SourceFiles:
-CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
+CHECK-NEXT: - 'c:\src{{[\\/]}}pdb_lines_2.c'
CHECK: Subsections:
-CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
+CHECK: - FileName: 'c:\src{{[\\/]}}pdb_lines_2.c'
CHECK: - !FileChecksums
-CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c'
+CHECK: - FileName: 'c:\src{{[\\/]}}pdb_lines_2.c'
+
+CHECK-LABEL: - Kind: S_ENVBLOCK
+CHECK-NEXT: EnvBlockSym:
+CHECK-NEXT: Entries:
+CHECK-NEXT: - cwd
+CHECK-NEXT: - 'c:\src'
+CHECK-NEXT: - exe
+CHECK-NEXT: - 'c:\src{{[\\/]}}lld-link'
+CHECK-NEXT: - pdb
+CHECK-NEXT: - 'c:\src{{[\\/]}}out.pdb'
+CHECK-NEXT: - cmd
+CHECK-NEXT: - '-debug -pdbsourcepath:c:\src -entry:main -nodefaultlib -out:out.exe -pdb:out.pdb pdb_lines_1_relative.obj pdb_lines_2_relative.obj'
+
+
+POSIX-LABEL: - Module: '/usr/src{{[\\/]}}pdb_lines_1_relative.obj'
+POSIX-NEXT: ObjFile: '/usr/src{{[\\/]}}pdb_lines_1_relative.obj'
+POSIX: SourceFiles:
+POSIX-NEXT: - '/usr/src{{[\\/]}}pdb_lines_1.c'
+POSIX-NEXT: - '/usr/src{{[\\/]}}foo.h'
+POSIX: Subsections:
+POSIX: - FileName: '/usr/src{{[\\/]}}pdb_lines_1.c'
+POSIX: - FileName: '/usr/src{{[\\/]}}foo.h'
+POSIX: - !FileChecksums
+POSIX: - FileName: '/usr/src{{[\\/]}}pdb_lines_1.c'
+POSIX: - FileName: '/usr/src{{[\\/]}}foo.h'
+
+POSIX-LABEL: - Module: '/usr/src{{[\\/]}}pdb_lines_2_relative.obj'
+POSIX-NEXT: ObjFile: '/usr/src{{[\\/]}}pdb_lines_2_relative.obj'
+POSIX: SourceFiles:
+POSIX-NEXT: - '/usr/src{{[\\/]}}pdb_lines_2.c'
+POSIX: Subsections:
+POSIX: - FileName: '/usr/src{{[\\/]}}pdb_lines_2.c'
+POSIX: - !FileChecksums
+POSIX: - FileName: '/usr/src{{[\\/]}}pdb_lines_2.c'
+
+POSIX-LABEL: - Kind: S_ENVBLOCK
+POSIX-NEXT: EnvBlockSym:
+POSIX-NEXT: Entries:
+POSIX-NEXT: - cwd
+POSIX-NEXT: - '/usr/src'
+POSIX-NEXT: - exe
+POSIX-NEXT: - '/usr/src{{[\\/]}}lld-link'
+POSIX-NEXT: - pdb
+POSIX-NEXT: - '/usr/src{{[\\/]}}out.pdb'
+POSIX-NEXT: - cmd
+POSIX-NEXT: - '-debug -pdbsourcepath:/usr/src -entry:main -nodefaultlib -out:out.exe -pdb:out.pdb pdb_lines_1_relative.obj pdb_lines_2_relative.obj'
diff --git a/test/COFF/pdb-same-name.test b/test/COFF/pdb-same-name.test
index 352bfc9f9942..52535107ca16 100644
--- a/test/COFF/pdb-same-name.test
+++ b/test/COFF/pdb-same-name.test
@@ -14,10 +14,10 @@
RAW: Modules
RAW-NEXT: ============================================================
RAW-NEXT: Mod 0000 | `foo.obj`:
-RAW-NEXT: Obj: `{{.*}}1\foo.lib`:
+RAW-NEXT: Obj: `{{.*}}1{{[\\/]}}foo.lib`:
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: Obj: `{{.*}}2{{[\\/]}}foo.lib`:
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-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml
index 0ed1215ec8ee..d8741afd8cde 100644
--- a/test/COFF/pdb-symbol-types.yaml
+++ b/test/COFF/pdb-symbol-types.yaml
@@ -17,9 +17,13 @@
# CHECK-NEXT: ============================================================
# CHECK-NEXT: Records
# CHECK-NEXT: 48 | S_PROCREF [size = 20] `main`
-# CHECK-NEXT: module = 1, sum name = 0, offset = 116
+# CHECK-NEXT: module = 1, sum name = 0, offset = 116
+# CHECK-NEXT: 96 | S_UDT [size = 16] `UDT_Foo`
+# CHECK-NEXT: original type = 0x1004
+# CHECK-NEXT: 112 | S_UDT [size = 12] `Foo`
+# CHECK-NEXT: original type = 0x1004
# CHECK-NEXT: 68 | S_GDATA32 [size = 28] `global_foo`
-# CHECK-NEXT: type = 0x1004 (Foo), addr = 0003:0000
+# CHECK-NEXT: type = 0x1004 (Foo), addr = 0003:0000
# CHECK: Symbols
# CHECK: ============================================================
diff --git a/test/COFF/pdb-thunk.yaml b/test/COFF/pdb-thunk.yaml
index 444800ff9e57..6435a17e8f62 100644
--- a/test/COFF/pdb-thunk.yaml
+++ b/test/COFF/pdb-thunk.yaml
@@ -84,7 +84,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4097
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -124,7 +124,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4121
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -164,7 +164,7 @@ sections:
RegRelativeSym:
Offset: 48
Type: 4143
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -208,7 +208,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4143
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2176,7 +2176,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4097
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
@@ -2222,7 +2222,7 @@ sections:
RegRelativeSym:
Offset: 8
Type: 4121
- Register: CVRegRSP
+ Register: RSP
VarName: this
- Kind: S_PROC_ID_END
ScopeEndSym:
diff --git a/test/COFF/pdb-type-server-invalid-signature.yaml b/test/COFF/pdb-type-server-invalid-signature.yaml
new file mode 100644
index 000000000000..247e00096235
--- /dev/null
+++ b/test/COFF/pdb-type-server-invalid-signature.yaml
@@ -0,0 +1,140 @@
+
+# RUN: cd %S/Inputs
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
+# RUN: cd %S
+
+# CHECK: warning: Cannot use debug info for {{.*}}.obj
+# CHECK-NEXT: The signature does not match; the file(s) might be out of date
+
+# Also test a valid match
+
+# RUN: cd %S/Inputs
+# RUN: yaml2obj %S/Inputs/pdb-type-server-valid-signature.yaml -o %t2.obj
+# RUN: lld-link %t2.obj -out:%t2.exe -debug -pdb:%t2.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=VALID-SIGNATURE -allow-empty
+# RUN: cd %S
+
+# VALID-SIGNATURE-NOT: warning: Cannot use debug info for {{.*}}.obj
+# VALID-SIGNATURE-NOT: The signature does not match; the file(s) might be out of date
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 3
+ DbgStart: 0
+ DbgEnd: 2
+ FunctionType: 4199
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 0
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 3
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Lines:
+ - Offset: 0
+ LineStart: 1
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Kind: MD5
+ Checksum: 270A878DCC1B845655B162F56C4F5020
+ - !StringTable
+ Strings:
+ - 'c:\src\llvm-project\build\t.c'
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 100
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ 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: 1
+ Types:
+ - Kind: LF_TYPESERVER2
+ TypeServer2:
+ Guid: '{01DF191B-22BF-6B42-96CE-5258B8329FE5}'
+ Age: 18
+ Name: 'pdb-diff-cl.pdb'
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 33C0C3
+symbols:
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 328
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 564
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 3
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 4021952397
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-type-server-missing.yaml b/test/COFF/pdb-type-server-missing.yaml
index fbbb46f6b4fd..1a8c9a05c3d9 100644
--- a/test/COFF/pdb-type-server-missing.yaml
+++ b/test/COFF/pdb-type-server-missing.yaml
@@ -1,10 +1,25 @@
# 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.
+# Also try linking another OBJ with a reference to the same PDB
-# RUN: yaml2obj %s -o %t.obj
-# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
+# RUN: yaml2obj %s -o %t1.obj
+# RUN: yaml2obj %p/Inputs/pdb-type-server-missing-2.yaml -o %t2.obj
+# RUN: lld-link %t1.obj %t2.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -check-prefix=WARN
+# RUN: lld-link %t1.obj %t2.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main /ignore:4099 2>&1 | FileCheck %s -check-prefix=IGNORE -allow-empty
+# RUN: not lld-link %t1.obj %t2.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main /WX 2>&1 | FileCheck %s -check-prefix=ERR
+# RUN: lld-link %t1.obj %t2.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main /ignore:4099 /WX 2>&1 | FileCheck %s -check-prefix=IGNORE-ERR -allow-empty
-# CHECK: warning: Type server PDB for {{.*}}.obj is invalid, ignoring debug info.
+# WARN: warning: Cannot use debug info for '{{.*}}.obj' [LNK4099]
+# WARN-NEXT: {{N|n}}o such file or directory
+
+# IGNORE-NOT: warning: Cannot use debug info for '{{.*}}.obj' [LNK4099]
+# IGNORE-NOT: {{N|n}}o such file or directory
+
+# ERR: error: Cannot use debug info for '{{.*}}.obj' [LNK4099]
+# ERR-NEXT: {{N|n}}o such file or directory
+
+# IGNORE-ERR-NOT: error: Cannot use debug info for '{{.*}}.obj' [LNK4099]
+# IGNORE-ERR-NOT: {{N|n}}o such file or directory
--- !COFF
header:
diff --git a/test/COFF/pdb-type-server-native-errors.yaml b/test/COFF/pdb-type-server-native-errors.yaml
new file mode 100644
index 000000000000..bc865411b3ad
--- /dev/null
+++ b/test/COFF/pdb-type-server-native-errors.yaml
@@ -0,0 +1,130 @@
+
+# RUN: cd %S/Inputs
+# RUN: yaml2obj %s -o %t.obj
+# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s
+# RUN: cd %S
+
+# CHECK: warning: Cannot use debug info for {{.*}}.obj
+# CHECK-NEXT: The PDB file is corrupt. MSF superblock is missing
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: [ ]
+sections:
+ - Name: '.debug$S'
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ]
+ Alignment: 1
+ Subsections:
+ - !Symbols
+ Records:
+ - Kind: S_GPROC32_ID
+ ProcSym:
+ CodeSize: 3
+ DbgStart: 0
+ DbgEnd: 2
+ FunctionType: 4199
+ Flags: [ ]
+ DisplayName: main
+ - Kind: S_FRAMEPROC
+ FrameProcSym:
+ TotalFrameBytes: 0
+ PaddingFrameBytes: 0
+ OffsetToPadding: 0
+ BytesOfCalleeSavedRegisters: 0
+ OffsetOfExceptionHandler: 0
+ SectionIdOfExceptionHandler: 0
+ Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ]
+ - Kind: S_PROC_ID_END
+ ScopeEndSym:
+ - !Lines
+ CodeSize: 3
+ Flags: [ ]
+ RelocOffset: 0
+ RelocSegment: 0
+ Blocks:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Lines:
+ - Offset: 0
+ LineStart: 1
+ IsStatement: true
+ EndDelta: 0
+ Columns:
+ - !FileChecksums
+ Checksums:
+ - FileName: 'c:\src\llvm-project\build\t.c'
+ Kind: MD5
+ Checksum: 270A878DCC1B845655B162F56C4F5020
+ - !StringTable
+ Strings:
+ - 'c:\src\llvm-project\build\t.c'
+ Relocations:
+ - VirtualAddress: 44
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 48
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECTION
+ - VirtualAddress: 100
+ SymbolName: main
+ Type: IMAGE_REL_AMD64_SECREL
+ - VirtualAddress: 104
+ 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: 1
+ Types:
+ - Kind: LF_TYPESERVER2
+ TypeServer2:
+ Guid: '{01DF191B-22BF-6B42-96CE-5258B8329FE5}'
+ Age: 18
+ Name: 'bad-block-size.pdb'
+ - Name: '.text$mn'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: 33C0C3
+symbols:
+ - Name: '.debug$S'
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 328
+ NumberOfRelocations: 4
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.debug$T'
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 564
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: '.text$mn'
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 3
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 4021952397
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 3
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test
index 51a92db8df7a..f69a34a98855 100644
--- a/test/COFF/pdb-type-server-simple.test
+++ b/test/COFF/pdb-type-server-simple.test
@@ -62,10 +62,12 @@ CHECK: {{.*}}: `b.c`
CHECK-LABEL: Global Symbols
CHECK: ============================================================
CHECK-NEXT: Records
-CHECK-NEXT: 36 | S_PROCREF [size = 20] `main`
-CHECK-NEXT: module = 1, sum name = 0, offset = 104
-CHECK-NEXT: 56 | S_PROCREF [size = 16] `g`
-CHECK-NEXT: module = 2, sum name = 0, offset = 104
+CHECK-NEXT: 36 | S_PROCREF [size = 20] `main`
+CHECK-NEXT: module = 1, sum name = 0, offset = 104
+CHECK-NEXT: 68 | S_PROCREF [size = 16] `g`
+CHECK-NEXT: module = 2, sum name = 0, offset = 104
+CHECK-NEXT: 56 | S_UDT [size = 12] `Foo`
+CHECK-NEXT: original type = 0x1006
CHECK-LABEL: Symbols
CHECK: ============================================================
@@ -89,7 +91,7 @@ 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 = CVRegRSP, offset = 8
+CHECK: type = [[FOO_PTR]] (Foo*), register = RSP, 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 a7b2a215ec6b..5788b516ad84 100644
--- a/test/COFF/pdb.test
+++ b/test/COFF/pdb.test
@@ -193,25 +193,6 @@ RAW-NEXT: flags = function, addr = 0001:0000
RAW-NEXT: 0 | S_PUB32 [size = 20] `foo`
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
diff --git a/test/COFF/pdbaltpath.test b/test/COFF/pdbaltpath.test
new file mode 100644
index 000000000000..952e208867ef
--- /dev/null
+++ b/test/COFF/pdbaltpath.test
@@ -0,0 +1,39 @@
+# RUN: yaml2obj %p/Inputs/empty.yaml > %t.obj
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:hello.pdb
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix HELLO %s
+# HELLO: PDBFileName: hello.pdb
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:%_Pdb%
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix PDBVAR %s
+# PDBVAR: PDBFileName: pdbaltpath.test.tmp.pdb
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_ExT%.pdb
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix EXTVAR %s
+# EXTVAR: PDBFileName: fooexe.pdb
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:%_PDB
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE %s
+# NOCLOSE: PDBFileName: %_PDB
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix NOCLOSE2 %s
+# NOCLOSE2: PDBFileName: foo%_PDB
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSEONE %s
+# CLOSEONE: PDBFileName: foopdbaltpath.test.tmp.pdbbar%_EXT
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT%
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO %s
+# CLOSETWO: PDBFileName: foopdbaltpath.test.tmp.pdbbarexe
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%_PDB%bar%_EXT%a
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix CLOSETWO2 %s
+# CLOSETWO2: PDBFileName: foopdbaltpath.test.tmp.pdbbarexea
+
+# RUN: lld-link /entry:main %t.obj /out:%t.exe /debug /pdbaltpath:foo%FoO%bar%r%a 2>&1 | FileCheck --check-prefix UNKNOWN-WARN %s
+# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck --check-prefix ENVVARS %s
+# UNKNOWN-WARN: only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping %FoO% as literal
+# UNKNOWN-WARN: only %_PDB% and %_EXT% supported in /pdbaltpath:, keeping %r% as literal
+# ENVVARS: PDBFileName: foo%FoO%bar%r%a
diff --git a/test/COFF/precomp-link.test b/test/COFF/precomp-link.test
new file mode 100644
index 000000000000..b60b0b2f1d77
--- /dev/null
+++ b/test/COFF/precomp-link.test
@@ -0,0 +1,42 @@
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf
+RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
+
+RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf
+RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
+
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-invalid.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE
+
+RUN: not lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf 2>&1 | FileCheck %s -check-prefix FAILURE-MISSING-PRECOMPOBJ
+
+FAILURE: warning: Cannot use debug info for 'precomp-invalid.obj' [LNK4099]
+FAILURE-NEXT: failed to load reference '{{.*}}precomp.obj': The signature does not match; the file(s) might be out of date.
+
+FAILURE-MISSING-PRECOMPOBJ: warning: Cannot use debug info for 'precomp-a.obj' [LNK4099]
+FAILURE-MISSING-PRECOMPOBJ-NEXT: failed to load reference '{{.*}}precomp.obj': The path to this file must be provided on the command-line
+
+CHECK: Types (TPI Stream)
+CHECK-NOT: LF_PRECOMP
+CHECK-NOT: LF_ENDPRECOMP
+
+// precomp.h
+#pragma once
+int Function(char A);
+
+// precomp.cpp
+#include "precomp.h"
+
+// a.cpp
+#include "precomp.h"
+int main(void) {
+ Function('a');
+ return 0;
+}
+
+// b.cpp
+#include "precomp.h"
+int Function(char a) {
+ return (int)a;
+}
+
+// cl.exe precomp.cpp /Z7 /Ycprecomp.h /c
+// cl.exe a.cpp b.cpp /Z7 /Yuprecomp.h /c
diff --git a/test/COFF/reloc-discarded.s b/test/COFF/reloc-discarded.s
index aa8fb3c3447a..378804b62312 100644
--- a/test/COFF/reloc-discarded.s
+++ b/test/COFF/reloc-discarded.s
@@ -10,6 +10,7 @@
# RUN: not lld-link -entry:main -nodefaultlib %t1.obj %t2.obj -out:%t.exe -opt:noref 2>&1 | FileCheck %s
# CHECK: error: relocation against symbol in discarded section: assoc_global
+# CHECK: >>> referenced by {{.*}}reloc-discarded{{.*}}.obj:(main)
.section .bss,"bw",discard,main_global
.globl main_global
diff --git a/test/COFF/rsds.test b/test/COFF/rsds.test
index 6ce92a9c5b03..b2c1be7478f5 100644
--- a/test/COFF/rsds.test
+++ b/test/COFF/rsds.test
@@ -1,9 +1,9 @@
# RUN: yaml2obj %s > %t.obj
# RUN: rm -f %t.dll %t.pdb
-# RUN: lld-link /debug /pdbaltpath:test1.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test.pdb /dll /out:%t.dll /entry:DllMain %t.obj
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt
-# RUN: lld-link /debug /pdbaltpath:test2.pdb /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: lld-link /debug /pdbaltpath:test.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
@@ -12,7 +12,19 @@
# RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt
# 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
+# RUN: cat %t.3.txt %t.4.txt | FileCheck --check-prefix TWOPDBS %s
+
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /Brepro /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRO %s
+
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /Brepro /debug /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix REPRODEBUG %s
+
+# RUN: rm -f %t.dll %t.pdb
+# RUN: lld-link /lldmingw /debug:dwarf /dll /out:%t.dll /entry:DllMain %t.obj
+# RUN: llvm-readobj -coff-debug-directory %t.dll | FileCheck --check-prefix MINGW %s
# CHECK: File: [[FILE:.*]].dll
# CHECK: DebugDirectory [
@@ -29,7 +41,7 @@
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
# CHECK: PDBAge: 1
-# CHECK: PDBFileName: {{.*}}1.pdb
+# CHECK: PDBFileName: {{.*}}.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
@@ -47,12 +59,114 @@
# CHECK: PDBInfo {
# CHECK: PDBSignature: 0x53445352
# CHECK: PDBGUID: [[GUID]]
-# CHECK: PDBAge: 2
-# CHECK: PDBFileName: {{.*}}2.pdb
+# CHECK: PDBAge: 1
+# CHECK: PDBFileName: {{.*}}.pdb
# CHECK: }
# CHECK: }
# CHECK: ]
+# TWOPDBS: File: [[FILE:.*]].dll
+# TWOPDBS: DebugDirectory [
+# TWOPDBS: DebugEntry {
+# TWOPDBS: Characteristics: 0x0
+# TWOPDBS: TimeDateStamp:
+# TWOPDBS: MajorVersion: 0x0
+# TWOPDBS: MinorVersion: 0x0
+# TWOPDBS: Type: CodeView (0x2)
+# TWOPDBS: SizeOfData: 0x{{[^0]}}
+# TWOPDBS: AddressOfRawData: 0x{{[^0]}}
+# TWOPDBS: PointerToRawData: 0x{{[^0]}}
+# TWOPDBS: PDBInfo {
+# TWOPDBS: PDBSignature: 0x53445352
+# TWOPDBS: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
+# TWOPDBS: PDBAge: 1
+# TWOPDBS: PDBFileName: {{.*}}.pdb
+# TWOPDBS: }
+# TWOPDBS: }
+# TWOPDBS: ]
+# TWOPDBS: File: [[FILE]].dll
+# TWOPDBS: DebugDirectory [
+# TWOPDBS: DebugEntry {
+# TWOPDBS: Characteristics: 0x0
+# TWOPDBS: TimeDateStamp:
+# TWOPDBS: MajorVersion: 0x0
+# TWOPDBS: MinorVersion: 0x0
+# TWOPDBS: Type: CodeView (0x2)
+# TWOPDBS: SizeOfData: 0x{{[^0]}}
+# TWOPDBS: AddressOfRawData: 0x{{[^0]}}
+# TWOPDBS: PointerToRawData: 0x{{[^0]}}
+# TWOPDBS: PDBInfo {
+# TWOPDBS: PDBSignature: 0x53445352
+# TWOPDBS-NOT: PDBGUID: [[GUID]]
+# TWOPDBS: PDBAge: 1
+# TWOPDBS: PDBFileName: {{.*}}.pdb
+# TWOPDBS: }
+# TWOPDBS: }
+# TWOPDBS: ]
+
+# REPRO: File: {{.*}}.dll
+# REPRO: DebugDirectory [
+# REPRO: DebugEntry {
+# REPRO: Characteristics: 0x0
+# REPRO: TimeDateStamp:
+# REPRO: MajorVersion: 0x0
+# REPRO: MinorVersion: 0x0
+# REPRO: Type: Repro (0x10)
+# REPRO: SizeOfData: 0x0
+# REPRO: AddressOfRawData: 0x0
+# REPRO: PointerToRawData: 0x0
+# REPRO: }
+# REPRO: ]
+
+# REPRODEBUG: File: {{.*}}.dll
+# REPRODEBUG: DebugDirectory [
+# REPRODEBUG: DebugEntry {
+# REPRODEBUG: Characteristics: 0x0
+# REPRODEBUG: TimeDateStamp:
+# REPRODEBUG: MajorVersion: 0x0
+# REPRODEBUG: MinorVersion: 0x0
+# REPRODEBUG: Type: CodeView (0x2)
+# REPRODEBUG: SizeOfData: 0x{{[^0]}}
+# REPRODEBUG: AddressOfRawData: 0x{{[^0]}}
+# REPRODEBUG: PointerToRawData: 0x{{[^0]}}
+# REPRODEBUG: PDBInfo {
+# REPRODEBUG: PDBSignature: 0x53445352
+# REPRODEBUG: PDBGUID:
+# REPRODEBUG: PDBAge: 1
+# REPRODEBUG: PDBFileName:
+# REPRODEBUG: }
+# REPRODEBUG: }
+# REPRODEBUG: DebugEntry {
+# REPRODEBUG: Characteristics: 0x0
+# REPRODEBUG: TimeDateStamp:
+# REPRODEBUG: MajorVersion: 0x0
+# REPRODEBUG: MinorVersion: 0x0
+# REPRODEBUG: Type: Repro (0x10)
+# REPRODEBUG: SizeOfData: 0x0
+# REPRODEBUG: AddressOfRawData: 0x0
+# REPRODEBUG: PointerToRawData: 0x0
+# REPRODEBUG: }
+# REPRODEBUG: ]
+
+# MINGW: File: {{.*}}.dll
+# MINGW: DebugDirectory [
+# MINGW: DebugEntry {
+# MINGW: Characteristics: 0x0
+# MINGW: TimeDateStamp:
+# MINGW: MajorVersion: 0x0
+# MINGW: MinorVersion: 0x0
+# MINGW: Type: CodeView (0x2)
+# MINGW: SizeOfData: 0x{{[^0]}}
+# MINGW: AddressOfRawData: 0x{{[^0]}}
+# MINGW: PointerToRawData: 0x{{[^0]}}
+# MINGW: PDBInfo {
+# MINGW: PDBSignature: 0x53445352
+# MINGW: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]]
+# MINGW: PDBAge: 1
+# MINGW: PDBFileName:
+# MINGW: }
+# MINGW: }
+# MINGW: ]
--- !COFF
header:
Machine: IMAGE_FILE_MACHINE_I386
diff --git a/test/COFF/s_udt.s b/test/COFF/s_udt.s
new file mode 100644
index 000000000000..8ad342e4e3d2
--- /dev/null
+++ b/test/COFF/s_udt.s
@@ -0,0 +1,476 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-windows-msvc < %s > %t.obj
+# RUN: lld-link /DEBUG:FULL /nodefaultlib /entry:main %t.obj /PDB:%t.pdb /OUT:%t.exe
+# RUN: llvm-pdbutil dump -types -globals -symbols -modi=0 %t.pdb | FileCheck %s
+
+# CHECK: Types (TPI Stream)
+# CHECK-NEXT: ============================================================
+# CHECK: 0x1003 | LF_STRUCTURE [size = 44] `Struct`
+# CHECK-NEXT: unique name: `.?AUStruct@@`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT: options: forward ref (-> 0x1006) | has unique name, sizeof 0
+# CHECK-NEXT: 0x1004 | LF_POINTER [size = 12]
+# CHECK-NEXT: referent = 0x1003, mode = pointer, opts = None, kind = ptr64
+# CHECK: 0x1006 | LF_STRUCTURE [size = 44] `Struct`
+# CHECK-NEXT: unique name: `.?AUStruct@@`
+# CHECK-NEXT: vtable: <no type>, base list: <no type>, field list: 0x1005
+# CHECK-NEXT: options: has unique name, sizeof 4
+# CHECK: Global Symbols
+# CHECK-NEXT: ============================================================
+# CHECK: {{.*}} | S_UDT [size = 24] `StructTypedef`
+# CHECK: original type = 0x1003
+# CHECK: {{.*}} | S_UDT [size = 16] `Struct`
+# CHECK: original type = 0x1006
+# CHECK: {{.*}} | S_UDT [size = 20] `IntTypedef`
+# CHECK: original type = 0x0074 (int)
+# CHECK: Symbols
+# CHECK-NEXT: ============================================================
+# CHECK: {{.*}} | S_GPROC32 [size = 44] `main`
+# CHECK-NEXT: parent = 0, end = 252, addr = 0001:0000, code size = 52
+# CHECK-NEXT: type = `0x1002 (int (int, char**))`, debug start = 0, debug end = 0, flags = none
+# CHECK-NOT: {{.*}} | S_END
+# CHECK: {{.*}} | S_UDT [size = 28] `main::LocalTypedef`
+# CHECK-NEXT: original type = 0x1004
+# CHECK: {{.*}} | S_END [size = 4]
+
+# source code to re-generate:
+# clang-cl /Z7 /GS- /GR- /c foo.cpp
+#
+# struct Struct {
+# int x;
+# };
+#
+# using IntTypedef = int;
+# using StructTypedef = Struct;
+# Struct S;
+# StructTypedef SS;
+# IntTypedef I;
+#
+# int main(int argc, char **argv) {
+# using LocalTypedef = Struct*;
+# LocalTypedef SPtr;
+# return I + S.x + SS.x + SPtr->x;
+# }
+
+ .text
+ .def @feat.00;
+ .scl 3;
+ .type 0;
+ .endef
+ .globl @feat.00
+.set @feat.00, 0
+ .intel_syntax noprefix
+ .def main;
+ .scl 2;
+ .type 32;
+ .endef
+ .globl main # -- Begin function main
+ .p2align 4, 0x90
+main: # @main
+.Lfunc_begin0:
+ .cv_func_id 0
+ .cv_file 1 "D:\\src\\llvmbuild\\cl\\Debug\\x64\\foo.cpp" "2B62298EE3EEF94E1D81FDFE18BD46A6" 1
+ .cv_loc 0 1 12 0 # foo.cpp:12:0
+.seh_proc main
+# %bb.0: # %entry
+ sub rsp, 32
+ .seh_stackalloc 32
+ .seh_endprologue
+ mov dword ptr [rsp + 28], 0
+ mov qword ptr [rsp + 16], rdx
+ mov dword ptr [rsp + 12], ecx
+.Ltmp0:
+ .cv_loc 0 1 15 0 # foo.cpp:15:0
+ mov ecx, dword ptr [rip + "?I@@3HA"]
+ add ecx, dword ptr [rip + "?S@@3UStruct@@A"]
+ add ecx, dword ptr [rip + "?SS@@3UStruct@@A"]
+ mov rdx, qword ptr [rsp]
+ add ecx, dword ptr [rdx]
+ mov eax, ecx
+ add rsp, 32
+ ret
+.Ltmp1:
+.Lfunc_end0:
+ .seh_handlerdata
+ .text
+ .seh_endproc
+ # -- End function
+ .bss
+ .globl "?S@@3UStruct@@A" # @"?S@@3UStruct@@A"
+ .p2align 2
+"?S@@3UStruct@@A":
+ .zero 4
+
+ .globl "?SS@@3UStruct@@A" # @"?SS@@3UStruct@@A"
+ .p2align 2
+"?SS@@3UStruct@@A":
+ .zero 4
+
+ .globl "?I@@3HA" # @"?I@@3HA"
+ .p2align 2
+"?I@@3HA":
+ .long 0 # 0x0
+
+ .section .drectve,"yn"
+ .ascii " /DEFAULTLIB:libcmt.lib"
+ .ascii " /DEFAULTLIB:oldnames.lib"
+ .section .debug$S,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ .long 241
+ .long .Ltmp3-.Ltmp2 # Subsection size
+.Ltmp2:
+ .short .Ltmp5-.Ltmp4 # Record length
+.Ltmp4:
+ .short 4412 # Record kind: S_COMPILE3
+ .long 1 # Flags and language
+ .short 208 # CPUType
+ .short 8 # Frontend version
+ .short 0
+ .short 0
+ .short 0
+ .short 8000 # Backend version
+ .short 0
+ .short 0
+ .short 0
+ .asciz "clang version 8.0.0 " # Null-terminated compiler version string
+.Ltmp5:
+.Ltmp3:
+ .p2align 2
+ .long 241 # Symbol subsection for main
+ .long .Ltmp7-.Ltmp6 # Subsection size
+.Ltmp6:
+ .short .Ltmp9-.Ltmp8 # Record length
+.Ltmp8:
+ .short 4423 # Record kind: S_GPROC32_ID
+ .long 0 # PtrParent
+ .long 0 # PtrEnd
+ .long 0 # PtrNext
+ .long .Lfunc_end0-main # Code size
+ .long 0 # Offset after prologue
+ .long 0 # Offset before epilogue
+ .long 4099 # Function type index
+ .secrel32 main # Function section relative address
+ .secidx main # Function section index
+ .byte 0 # Flags
+ .asciz "main" # Function name
+.Ltmp9:
+ .short .Ltmp11-.Ltmp10 # Record length
+.Ltmp10:
+ .short 4114 # Record kind: S_FRAMEPROC
+ .long 32 # FrameSize
+ .long 0 # Padding
+ .long 0 # Offset of padding
+ .long 0 # Bytes of callee saved registers
+ .long 0 # Exception handler offset
+ .short 0 # Exception handler section
+ .long 81920 # Flags (defines frame register)
+.Ltmp11:
+ .short .Ltmp13-.Ltmp12 # Record length
+.Ltmp12:
+ .short 4414 # Record kind: S_LOCAL
+ .long 116 # TypeIndex
+ .short 1 # Flags
+ .asciz "argc"
+.Ltmp13:
+ .cv_def_range .Ltmp0 .Ltmp1, "B\021\f\000\000\000"
+ .short .Ltmp15-.Ltmp14 # Record length
+.Ltmp14:
+ .short 4414 # Record kind: S_LOCAL
+ .long 4096 # TypeIndex
+ .short 1 # Flags
+ .asciz "argv"
+.Ltmp15:
+ .cv_def_range .Ltmp0 .Ltmp1, "B\021\020\000\000\000"
+ .short .Ltmp17-.Ltmp16 # Record length
+.Ltmp16:
+ .short 4414 # Record kind: S_LOCAL
+ .long 4101 # TypeIndex
+ .short 0 # Flags
+ .asciz "SPtr"
+.Ltmp17:
+ .cv_def_range .Ltmp0 .Ltmp1, "B\021\000\000\000\000"
+ .short .Ltmp19-.Ltmp18 # Record length
+.Ltmp18:
+ .short 4360 # Record kind: S_UDT
+ .long 4101 # Type
+ .asciz "main::LocalTypedef"
+.Ltmp19:
+ .short 2 # Record length
+ .short 4431 # Record kind: S_PROC_ID_END
+.Ltmp7:
+ .p2align 2
+ .cv_linetable 0, main, .Lfunc_end0
+ .long 241 # Symbol subsection for globals
+ .long .Ltmp21-.Ltmp20 # Subsection size
+.Ltmp20:
+ .short .Ltmp23-.Ltmp22 # Record length
+.Ltmp22:
+ .short 4365 # Record kind: S_GDATA32
+ .long 4103 # Type
+ .secrel32 "?S@@3UStruct@@A" # DataOffset
+ .secidx "?S@@3UStruct@@A" # Segment
+ .asciz "S" # Name
+.Ltmp23:
+ .short .Ltmp25-.Ltmp24 # Record length
+.Ltmp24:
+ .short 4365 # Record kind: S_GDATA32
+ .long 4100 # Type
+ .secrel32 "?SS@@3UStruct@@A" # DataOffset
+ .secidx "?SS@@3UStruct@@A" # Segment
+ .asciz "SS" # Name
+.Ltmp25:
+ .short .Ltmp27-.Ltmp26 # Record length
+.Ltmp26:
+ .short 4365 # Record kind: S_GDATA32
+ .long 116 # Type
+ .secrel32 "?I@@3HA" # DataOffset
+ .secidx "?I@@3HA" # Segment
+ .asciz "I" # Name
+.Ltmp27:
+.Ltmp21:
+ .p2align 2
+ .long 241
+ .long .Ltmp29-.Ltmp28 # Subsection size
+.Ltmp28:
+ .short .Ltmp31-.Ltmp30 # Record length
+.Ltmp30:
+ .short 4360 # Record kind: S_UDT
+ .long 4103 # Type
+ .asciz "Struct"
+.Ltmp31:
+ .short .Ltmp33-.Ltmp32 # Record length
+.Ltmp32:
+ .short 4360 # Record kind: S_UDT
+ .long 4100 # Type
+ .asciz "StructTypedef"
+.Ltmp33:
+ .short .Ltmp35-.Ltmp34 # Record length
+.Ltmp34:
+ .short 4360 # Record kind: S_UDT
+ .long 116 # Type
+ .asciz "IntTypedef"
+.Ltmp35:
+.Ltmp29:
+ .p2align 2
+ .cv_filechecksums # File index to string table offset subsection
+ .cv_stringtable # String table
+ .long 241
+ .long .Ltmp37-.Ltmp36 # Subsection size
+.Ltmp36:
+ .short 6 # Record length
+ .short 4428 # Record kind: S_BUILDINFO
+ .long 4108 # LF_BUILDINFO index
+.Ltmp37:
+ .p2align 2
+ .section .debug$T,"dr"
+ .p2align 2
+ .long 4 # Debug section magic
+ # Pointer (0x1000) {
+ # TypeLeafKind: LF_POINTER (0x1002)
+ # PointeeType: char* (0x670)
+ # PtrType: Near64 (0xC)
+ # PtrMode: Pointer (0x0)
+ # IsFlat: 0
+ # IsConst: 0
+ # IsVolatile: 0
+ # IsUnaligned: 0
+ # IsRestrict: 0
+ # IsThisPtr&: 0
+ # IsThisPtr&&: 0
+ # SizeOf: 8
+ # }
+ .byte 0x0a, 0x00, 0x02, 0x10
+ .byte 0x70, 0x06, 0x00, 0x00
+ .byte 0x0c, 0x00, 0x01, 0x00
+ # ArgList (0x1001) {
+ # TypeLeafKind: LF_ARGLIST (0x1201)
+ # NumArgs: 2
+ # Arguments [
+ # ArgType: int (0x74)
+ # ArgType: char** (0x1000)
+ # ]
+ # }
+ .byte 0x0e, 0x00, 0x01, 0x12
+ .byte 0x02, 0x00, 0x00, 0x00
+ .byte 0x74, 0x00, 0x00, 0x00
+ .byte 0x00, 0x10, 0x00, 0x00
+ # Procedure (0x1002) {
+ # TypeLeafKind: LF_PROCEDURE (0x1008)
+ # ReturnType: int (0x74)
+ # CallingConvention: NearC (0x0)
+ # FunctionOptions [ (0x0)
+ # ]
+ # NumParameters: 2
+ # ArgListType: (int, char**) (0x1001)
+ # }
+ .byte 0x0e, 0x00, 0x08, 0x10
+ .byte 0x74, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x02, 0x00
+ .byte 0x01, 0x10, 0x00, 0x00
+ # FuncId (0x1003) {
+ # TypeLeafKind: LF_FUNC_ID (0x1601)
+ # ParentScope: 0x0
+ # FunctionType: int (int, char**) (0x1002)
+ # Name: main
+ # }
+ .byte 0x12, 0x00, 0x01, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x02, 0x10, 0x00, 0x00
+ .byte 0x6d, 0x61, 0x69, 0x6e
+ .byte 0x00, 0xf3, 0xf2, 0xf1
+ # Struct (0x1004) {
+ # TypeLeafKind: LF_STRUCTURE (0x1505)
+ # MemberCount: 0
+ # Properties [ (0x280)
+ # ForwardReference (0x80)
+ # HasUniqueName (0x200)
+ # ]
+ # FieldList: 0x0
+ # DerivedFrom: 0x0
+ # VShape: 0x0
+ # SizeOf: 0
+ # Name: Struct
+ # LinkageName: .?AUStruct@@
+ # }
+ .byte 0x2a, 0x00, 0x05, 0x15
+ .byte 0x00, 0x00, 0x80, 0x02
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x53, 0x74
+ .byte 0x72, 0x75, 0x63, 0x74
+ .byte 0x00, 0x2e, 0x3f, 0x41
+ .byte 0x55, 0x53, 0x74, 0x72
+ .byte 0x75, 0x63, 0x74, 0x40
+ .byte 0x40, 0x00, 0xf2, 0xf1
+ # Pointer (0x1005) {
+ # TypeLeafKind: LF_POINTER (0x1002)
+ # PointeeType: Struct (0x1004)
+ # PtrType: Near64 (0xC)
+ # PtrMode: Pointer (0x0)
+ # IsFlat: 0
+ # IsConst: 0
+ # IsVolatile: 0
+ # IsUnaligned: 0
+ # IsRestrict: 0
+ # IsThisPtr&: 0
+ # IsThisPtr&&: 0
+ # SizeOf: 8
+ # }
+ .byte 0x0a, 0x00, 0x02, 0x10
+ .byte 0x04, 0x10, 0x00, 0x00
+ .byte 0x0c, 0x00, 0x01, 0x00
+ # FieldList (0x1006) {
+ # TypeLeafKind: LF_FIELDLIST (0x1203)
+ # DataMember {
+ # TypeLeafKind: LF_MEMBER (0x150D)
+ # AccessSpecifier: Public (0x3)
+ # Type: int (0x74)
+ # FieldOffset: 0x0
+ # Name: x
+ # }
+ # }
+ .byte 0x0e, 0x00, 0x03, 0x12
+ .byte 0x0d, 0x15, 0x03, 0x00
+ .byte 0x74, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x78, 0x00
+ # Struct (0x1007) {
+ # TypeLeafKind: LF_STRUCTURE (0x1505)
+ # MemberCount: 1
+ # Properties [ (0x200)
+ # HasUniqueName (0x200)
+ # ]
+ # FieldList: <field list> (0x1006)
+ # DerivedFrom: 0x0
+ # VShape: 0x0
+ # SizeOf: 4
+ # Name: Struct
+ # LinkageName: .?AUStruct@@
+ # }
+ .byte 0x2a, 0x00, 0x05, 0x15
+ .byte 0x01, 0x00, 0x00, 0x02
+ .byte 0x06, 0x10, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x04, 0x00, 0x53, 0x74
+ .byte 0x72, 0x75, 0x63, 0x74
+ .byte 0x00, 0x2e, 0x3f, 0x41
+ .byte 0x55, 0x53, 0x74, 0x72
+ .byte 0x75, 0x63, 0x74, 0x40
+ .byte 0x40, 0x00, 0xf2, 0xf1
+ # StringId (0x1008) {
+ # TypeLeafKind: LF_STRING_ID (0x1605)
+ # Id: 0x0
+ # StringData: D:\src\llvmbuild\cl\Debug\x64\foo.cpp
+ # }
+ .byte 0x2e, 0x00, 0x05, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x44, 0x3a, 0x5c, 0x73
+ .byte 0x72, 0x63, 0x5c, 0x6c
+ .byte 0x6c, 0x76, 0x6d, 0x62
+ .byte 0x75, 0x69, 0x6c, 0x64
+ .byte 0x5c, 0x63, 0x6c, 0x5c
+ .byte 0x44, 0x65, 0x62, 0x75
+ .byte 0x67, 0x5c, 0x78, 0x36
+ .byte 0x34, 0x5c, 0x66, 0x6f
+ .byte 0x6f, 0x2e, 0x63, 0x70
+ .byte 0x70, 0x00, 0xf2, 0xf1
+ # UdtSourceLine (0x1009) {
+ # TypeLeafKind: LF_UDT_SRC_LINE (0x1606)
+ # UDT: Struct (0x1007)
+ # SourceFile: D:\src\llvmbuild\cl\Debug\x64\foo.cpp (0x1008)
+ # LineNumber: 1
+ # }
+ .byte 0x0e, 0x00, 0x06, 0x16
+ .byte 0x07, 0x10, 0x00, 0x00
+ .byte 0x08, 0x10, 0x00, 0x00
+ .byte 0x01, 0x00, 0x00, 0x00
+ # StringId (0x100A) {
+ # TypeLeafKind: LF_STRING_ID (0x1605)
+ # Id: 0x0
+ # StringData: D:\\src\\llvmbuild\\cl\\Debug\\x64
+ # }
+ .byte 0x2a, 0x00, 0x05, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x44, 0x3a, 0x5c, 0x5c
+ .byte 0x73, 0x72, 0x63, 0x5c
+ .byte 0x5c, 0x6c, 0x6c, 0x76
+ .byte 0x6d, 0x62, 0x75, 0x69
+ .byte 0x6c, 0x64, 0x5c, 0x5c
+ .byte 0x63, 0x6c, 0x5c, 0x5c
+ .byte 0x44, 0x65, 0x62, 0x75
+ .byte 0x67, 0x5c, 0x5c, 0x78
+ .byte 0x36, 0x34, 0x00, 0xf1
+ # StringId (0x100B) {
+ # TypeLeafKind: LF_STRING_ID (0x1605)
+ # Id: 0x0
+ # StringData: foo.cpp
+ # }
+ .byte 0x0e, 0x00, 0x05, 0x16
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x66, 0x6f, 0x6f, 0x2e
+ .byte 0x63, 0x70, 0x70, 0x00
+ # BuildInfo (0x100C) {
+ # TypeLeafKind: LF_BUILDINFO (0x1603)
+ # NumArgs: 5
+ # Arguments [
+ # ArgType: D:\\src\\llvmbuild\\cl\\Debug\\x64 (0x100A)
+ # ArgType: 0x0
+ # ArgType: foo.cpp (0x100B)
+ # ArgType: 0x0
+ # ArgType: 0x0
+ # ]
+ # }
+ .byte 0x1a, 0x00, 0x03, 0x16
+ .byte 0x05, 0x00, 0x0a, 0x10
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x0b, 0x10
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0x00, 0x00
+ .byte 0x00, 0x00, 0xf2, 0xf1
+
+ .addrsig
+ .addrsig_sym "?S@@3UStruct@@A"
+ .addrsig_sym "?SS@@3UStruct@@A"
+ .addrsig_sym "?I@@3HA"
diff --git a/test/COFF/subsystem-inference-mingw.s b/test/COFF/subsystem-inference-mingw.s
new file mode 100644
index 000000000000..3339e6408af1
--- /dev/null
+++ b/test/COFF/subsystem-inference-mingw.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.o
+
+# RUN: lld-link -lldmingw %t.o -out:%t.exe
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# CHECK: AddressOfEntryPoint: 0x1001
+# CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3)
+
+ .text
+ .globl foo
+ .globl mainCRTStartup
+foo:
+ ret
+mainCRTStartup:
+ call foo
+ ret
diff --git a/test/COFF/subsystem-inference2.test b/test/COFF/subsystem-inference2.test
new file mode 100644
index 000000000000..0c159a7ded55
--- /dev/null
+++ b/test/COFF/subsystem-inference2.test
@@ -0,0 +1,54 @@
+# RUN: yaml2obj %s > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj 2>&1 | FileCheck -check-prefix=WARN %s
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+# WARN: warning: found main and WinMain; defaulting to /subsystem:console
+# CHECK: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: B82A000000C3
+symbols:
+ - Name: .text
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_STATIC
+ SectionDefinition:
+ Length: 6
+ NumberOfRelocations: 0
+ NumberOfLinenumbers: 0
+ CheckSum: 0
+ Number: 0
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: WinMain
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: WinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/subsystem-inference32.test b/test/COFF/subsystem-inference32.test
new file mode 100644
index 000000000000..8e66a85a7920
--- /dev/null
+++ b/test/COFF/subsystem-inference32.test
@@ -0,0 +1,74 @@
+# RUN: sed -e s/ENTRYNAME/_main/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=MAIN %s
+
+# RUN: sed s/ENTRYNAME/_wmain/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WMAIN %s
+
+# RUN: sed s/ENTRYNAME/_WinMain@16/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WINMAIN %s
+
+# RUN: sed s/ENTRYNAME/_wWinMain@16/ %s | yaml2obj > %t.obj
+# RUN: lld-link /out:%t.exe %t.obj
+# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=WWINMAIN %s
+
+# MAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI
+# WINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+# WWINMAIN: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_GUI
+
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_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: ENTRYNAME
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _mainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _wmainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _WinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: _wWinMainCRTStartup
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/test/COFF/thinlto-archives.ll b/test/COFF/thinlto-archives.ll
index 9a47a3a6feb6..6a27115705b1 100644
--- a/test/COFF/thinlto-archives.ll
+++ b/test/COFF/thinlto-archives.ll
@@ -6,9 +6,17 @@
; RUN: opt -thinlto-bc -o %T/thinlto-archives/b/bar.obj %S/Inputs/bar.ll
; RUN: llvm-ar crs %T/thinlto-archives/a.lib %T/thinlto-archives/a/bar.obj
; RUN: llvm-ar crs %T/thinlto-archives/b.lib %T/thinlto-archives/b/bar.obj
-; RUN: lld-link /out:%T/thinlto-archives/main.exe -entry:main \
-; RUN: -subsystem:console %T/thinlto-archives/main.obj \
+; RUN: lld-link -out:%T/thinlto-archives/main.exe -entry:main \
+; RUN: -lldsavetemps -subsystem:console %T/thinlto-archives/main.obj \
; RUN: %T/thinlto-archives/a.lib %T/thinlto-archives/b.lib
+; RUN: FileCheck %s < %T/thinlto-archives/main.exe.resolution.txt
+
+; CHECK: {{/thinlto-archives/main.obj$}}
+; CHECK: {{^-r=.*/thinlto-archives/main.obj,main,px$}}
+; CHECK: {{/thinlto-archives/a.libbar.obj$}}
+; CHECK-NEXT: {{^-r=.*/thinlto-archives/a.libbar.obj,foo,p$}}
+; CHECK-NEXT: {{/thinlto-archives/b.libbar.obj$}}
+; CHECK-NEXT: {{^-r=.*/thinlto-archives/b.libbar.obj,bar,p$}}
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
diff --git a/test/COFF/undefined-symbol-cv.s b/test/COFF/undefined-symbol-cv.s
index 31a44c384c75..e730c5dfc9f4 100644
--- a/test/COFF/undefined-symbol-cv.s
+++ b/test/COFF/undefined-symbol-cv.s
@@ -2,19 +2,19 @@
# 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: error: undefined symbol: "int __cdecl foo(void)" (?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-EMPTY:
+# CHECK-NEXT: error: undefined symbol: "int __cdecl bar(void)" (?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-EMPTY:
+# CHECK-NEXT: error: undefined symbol: "int __cdecl baz(void)" (?baz@@YAHXZ)
# CHECK-NEXT: >>> referenced by file1.cpp:5
# CHECK-NEXT: >>> {{.*}}.obj:(f2)
diff --git a/test/COFF/undefined-symbol.s b/test/COFF/undefined-symbol.s
index 5d002d82d23c..31da50a9e181 100644
--- a/test/COFF/undefined-symbol.s
+++ b/test/COFF/undefined-symbol.s
@@ -2,15 +2,15 @@
# 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: error: undefined symbol: "int __cdecl foo(void)" (?foo@@YAHXZ)
# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
-
-# CHECK: error: undefined symbol: ?bar@@YAHXZ
+# CHECK-EMPTY:
+# CHECK-NEXT: error: undefined symbol: "int __cdecl bar(void)" (?bar@@YAHXZ)
# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main)
# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1)
-
-# CHECK: error: undefined symbol: ?baz@@YAHXZ
+# CHECK-EMPTY:
+# CHECK-NEXT: error: undefined symbol: "__declspec(dllimport) int __cdecl baz(void)" (__imp_?baz@@YAHXZ)
# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f2)
.section .text,"xr",one_only,main
@@ -27,4 +27,4 @@ f1:
.section .text,"xr",one_only,f2
.globl f2
f2:
- call "?baz@@YAHXZ"
+ callq *"__imp_?baz@@YAHXZ"(%rip)
diff --git a/test/COFF/wholearchive.s b/test/COFF/wholearchive.s
index 6a601eba6b0d..cb19d4ddde07 100644
--- a/test/COFF/wholearchive.s
+++ b/test/COFF/wholearchive.s
@@ -1,6 +1,7 @@
# REQUIRES: x86
# RUN: yaml2obj < %p/Inputs/export.yaml > %t.archive.obj
+# RUN: rm -f %t.archive.lib
# RUN: llvm-ar rcs %t.archive.lib %t.archive.obj
# RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.main.obj
diff --git a/test/ELF/Inputs/bad-reloc-target.test b/test/ELF/Inputs/bad-reloc-target.test
new file mode 100644
index 000000000000..dabd005881f4
--- /dev/null
+++ b/test/ELF/Inputs/bad-reloc-target.test
@@ -0,0 +1,21 @@
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: 99
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ Global:
+ - Name: foo \ No newline at end of file
diff --git a/test/ELF/Inputs/copy-rel-tls.s b/test/ELF/Inputs/copy-rel-tls.s
new file mode 100644
index 000000000000..c34b6925e809
--- /dev/null
+++ b/test/ELF/Inputs/copy-rel-tls.s
@@ -0,0 +1,12 @@
+.bss
+.global foo
+.type foo, @object
+.size foo, 4
+foo:
+
+.section .tbss,"awT",@nobits
+.global tfoo
+.skip 0x2000
+.type tfoo,@object
+.size tfoo, 4
+tfoo:
diff --git a/test/ELF/Inputs/gdb-index-invalid-ranges.obj.s b/test/ELF/Inputs/gdb-index-invalid-ranges.obj.s
new file mode 100644
index 000000000000..d7e0bd29d2f8
--- /dev/null
+++ b/test/ELF/Inputs/gdb-index-invalid-ranges.obj.s
@@ -0,0 +1,2 @@
+main:
+ callq f1
diff --git a/test/ELF/Inputs/gdb-index-multiple-cu-2.s b/test/ELF/Inputs/gdb-index-multiple-cu-2.s
new file mode 100644
index 000000000000..80c738eab1ff
--- /dev/null
+++ b/test/ELF/Inputs/gdb-index-multiple-cu-2.s
@@ -0,0 +1,45 @@
+.globl _start
+_start:
+
+.section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .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 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0
+
+.section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Lcu_end0 - .Lcu_begin0 - 4
+ .short 4 # DWARF version number
+ .long 0 # Offset Into Abbrev. Section
+ .byte 4 # Address Size
+.Ldie:
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 2 # Abbrev [2] DW_TAG_subprogram
+ .asciz "_start" # DW_AT_name
+ .byte 0
+.Lcu_end0:
+
+# .debug_gnu_pubnames has just one set, associated with .Lcu_begin1 (CuIndex: 1)
+.section .debug_gnu_pubnames,"",@progbits
+ .long .LpubNames_end0 - .LpubNames_begin0
+.LpubNames_begin0:
+ .short 2 # Version
+ .long .Lcu_begin0 # CU Offset
+ .long .Lcu_end0 - .Lcu_begin0
+ .long .Ldie - .Lcu_begin0
+ .byte 48 # Attributes: FUNCTION, EXTERNAL
+ .asciz "_start" # External Name
+ .long 0
+.LpubNames_end0:
diff --git a/test/ELF/Inputs/hexagon-shared.s b/test/ELF/Inputs/hexagon-shared.s
new file mode 100644
index 000000000000..a014dd1e08db
--- /dev/null
+++ b/test/ELF/Inputs/hexagon-shared.s
@@ -0,0 +1,3 @@
+.global bar
+bar:
+ jumpr lr
diff --git a/test/ELF/Inputs/i386-linkonce.s b/test/ELF/Inputs/i386-linkonce.s
new file mode 100644
index 000000000000..b5906cc79657
--- /dev/null
+++ b/test/ELF/Inputs/i386-linkonce.s
@@ -0,0 +1,11 @@
+.section .gnu.linkonce.t.__i686.get_pc_thunk.bx
+.global __i686.get_pc_thunk.bx
+__i686.get_pc_thunk.bx:
+ mov (%esp),%ebx
+ ret
+
+.section .text
+.global _strchr1
+_strchr1:
+ call __i686.get_pc_thunk.bx
+ ret
diff --git a/test/ELF/Inputs/ppc64-bsymbolic-local-def.s b/test/ELF/Inputs/ppc64-bsymbolic-local-def.s
new file mode 100644
index 000000000000..10eec6ca3198
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-bsymbolic-local-def.s
@@ -0,0 +1,14 @@
+ .abiversion 2
+ .section ".text"
+
+ .p2align 2
+ .global def
+ .type def, @function
+def:
+.Ldef_gep:
+ addis 2, 12, .TOC.-.Ldef_gep@ha
+ addi 2, 2, .TOC.-.Ldef_gep@l
+.Ldef_lep:
+ .localentry def, .-def
+ li 3, 55
+ blr
diff --git a/test/ELF/Inputs/ppc64-no-split-stack.s b/test/ELF/Inputs/ppc64-no-split-stack.s
new file mode 100644
index 000000000000..83717677266d
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-no-split-stack.s
@@ -0,0 +1,8 @@
+ .abiversion 2
+ .p2align 2
+ .global nss_callee
+ .type nss_callee, @function
+nss_callee:
+ li 3, 1
+ blr
+
diff --git a/test/ELF/Inputs/ppc64-tls-ie-le.s b/test/ELF/Inputs/ppc64-tls-ie-le.s
new file mode 100644
index 000000000000..1d7ccc8f8875
--- /dev/null
+++ b/test/ELF/Inputs/ppc64-tls-ie-le.s
@@ -0,0 +1,29 @@
+ .text
+ .abiversion 2
+ .type c,@object # @c
+ .section .tdata,"awT",@progbits
+ .globl c
+c:
+ .byte 97 # 0x61
+ .size c, 1
+
+ .type s,@object # @s
+ .globl s
+ .p2align 1
+s:
+ .short 55 # 0x37
+ .size s, 2
+
+ .type i,@object # @i
+ .globl i
+ .p2align 2
+i:
+ .long 55 # 0x37
+ .size i, 4
+
+ .type l,@object # @l
+ .globl l
+ .p2align 3
+l:
+ .quad 55 # 0x37
+ .size l, 8
diff --git a/test/ELF/Inputs/ppc64le-quadword-ldst.o b/test/ELF/Inputs/ppc64le-quadword-ldst.o
new file mode 100644
index 000000000000..c17ef9e0209f
--- /dev/null
+++ b/test/ELF/Inputs/ppc64le-quadword-ldst.o
Binary files differ
diff --git a/test/ELF/Inputs/wrap-with-archive.s b/test/ELF/Inputs/wrap-with-archive.s
new file mode 100644
index 000000000000..93aaddc8806a
--- /dev/null
+++ b/test/ELF/Inputs/wrap-with-archive.s
@@ -0,0 +1,5 @@
+.global __executable_start
+.global __wrap_get_executable_start
+
+__wrap_get_executable_start:
+ movabs $__executable_start,%rdx
diff --git a/test/ELF/Inputs/x86-64-split-stack-extra.s b/test/ELF/Inputs/x86-64-split-stack-extra.s
new file mode 100644
index 000000000000..29c42185caa3
--- /dev/null
+++ b/test/ELF/Inputs/x86-64-split-stack-extra.s
@@ -0,0 +1,10 @@
+# This file is split out to provide better 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/aarch64-abs16.s b/test/ELF/aarch64-abs16.s
index 20a65b1cf4a8..c9d88b31ae35 100644
--- a/test/ELF/aarch64-abs16.s
+++ b/test/ELF/aarch64-abs16.s
@@ -14,14 +14,14 @@ _start:
// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
// CHECK: Contents of section .data:
-// 11000: S = 0x100, A = 0xfeff
-// S + A = 0xffff
-// 11002: S = 0x100, A = -0x8100
-// S + A = 0x8000
-// CHECK-NEXT: 20000 ffff0080
+// 210000: S = 0x100, A = 0xfeff
+// S + A = 0xffff
+// 210002: S = 0x100, A = -0x8100
+// S + A = 0x8000
+// CHECK-NEXT: 210000 ffff0080
-// RUN: not ld.lld %t.o %t255.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// RUN: not ld.lld %t.o %t257.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// OVERFLOW: Relocation R_AARCH64_ABS16 out of range: 65536 is not in [-32768, 65535]
+// RUN: not ld.lld %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1
+// OVERFLOW1: relocation R_AARCH64_ABS16 out of range: -32769 is not in [-32768, 32767]
+
+// RUN: not ld.lld %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2
+// OVERFLOW2: relocation R_AARCH64_ABS16 out of range: 65536 is not in [-32768, 32767]
diff --git a/test/ELF/aarch64-abs32.s b/test/ELF/aarch64-abs32.s
index b93f27a0bc4b..da2005dc97a6 100644
--- a/test/ELF/aarch64-abs32.s
+++ b/test/ELF/aarch64-abs32.s
@@ -14,14 +14,14 @@ _start:
// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
// CHECK: Contents of section .data:
-// 20000: S = 0x100, A = 0xfffffeff
-// S + A = 0xffffffff
-// 20004: S = 0x100, A = -0x80000100
-// S + A = 0x80000000
-// CHECK-NEXT: 20000 ffffffff 00000080
+// 210000: S = 0x100, A = 0xfffffeff
+// S + A = 0xffffffff
+// 210004: S = 0x100, A = -0x80000100
+// S + A = 0x80000000
+// CHECK-NEXT: 210000 ffffffff 00000080
-// RUN: not ld.lld %t.o %t255.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// RUN: not ld.lld %t.o %t257.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// OVERFLOW: Relocation R_AARCH64_ABS32 out of range: 4294967296 is not in [-2147483648, 4294967295]
+// RUN: not ld.lld %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1
+// OVERFLOW1: relocation R_AARCH64_ABS32 out of range: -2147483649 is not in [-2147483648, 2147483647]
+
+// RUN: not ld.lld %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2
+// OVERFLOW2: relocation R_AARCH64_ABS32 out of range: 4294967296 is not in [-2147483648, 2147483647]
diff --git a/test/ELF/aarch64-call26-thunk.s b/test/ELF/aarch64-call26-thunk.s
index 067f6dbc2f7e..1ca079946842 100644
--- a/test/ELF/aarch64-call26-thunk.s
+++ b/test/ELF/aarch64-call26-thunk.s
@@ -11,11 +11,11 @@ _start:
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
-// CHECK-NEXT: 20000: 02 00 00 94 bl #8
+// CHECK-NEXT: 210000: 02 00 00 94 bl #8
// CHECK: __AArch64AbsLongThunk_big:
-// CHECK-NEXT: 20008: 50 00 00 58 ldr x16, #8
-// CHECK-NEXT: 2000c: 00 02 1f d6 br x16
+// CHECK-NEXT: 210008: 50 00 00 58 ldr x16, #8
+// CHECK-NEXT: 21000c: 00 02 1f d6 br x16
// CHECK: $d:
-// CHECK-NEXT: 20010: 00 00 00 00 .word 0x00000000
-// CHECK-NEXT: 20014: 10 00 00 00 .word 0x00000010
+// CHECK-NEXT: 210010: 00 00 00 00 .word 0x00000000
+// CHECK-NEXT: 210014: 10 00 00 00 .word 0x00000010
diff --git a/test/ELF/aarch64-combined-dynrel-ifunc.s b/test/ELF/aarch64-combined-dynrel-ifunc.s
new file mode 100644
index 000000000000..5e84b03d7b2e
--- /dev/null
+++ b/test/ELF/aarch64-combined-dynrel-ifunc.s
@@ -0,0 +1,51 @@
+// REQUIRES: AArch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %p/Inputs/shared.s -o %t-lib.o
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t.o
+// RUN: ld.lld %t-lib.o --shared -o %t.so
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
+// RUN: } " > %t.script
+// RUN: ld.lld %t.o -o %t.axf %t.so --script %t.script
+// RUN: llvm-readobj --section-headers --dynamic-table %t.axf | FileCheck %s
+
+// The linker script above combines the .rela.dyn and .rela.plt into a single
+// table. ELF is clear that the DT_PLTRELSZ should match the subset of
+// relocations that is associated with the PLT. It is less clear about what
+// the value of DT_RELASZ should be. ELF implies that it should be the size
+// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
+// glibc permits this as long as .rela.plt comes after .rela.dyn in the
+// combined table. In the ARM case irelative relocations do not count as PLT
+// relocs. In the AArch64 case irelative relocations count as PLT relocs.
+
+.text
+.globl indirect
+.type indirect,@gnu_indirect_function
+indirect:
+ ret
+
+.globl bar // from Inputs/shared.s
+
+.text
+.globl _start
+.type _start,@function
+main:
+ bl indirect
+ bl bar
+ adrp x8, :got:indirect
+ ldr x8, [x8, :got_lo12:indirect]
+ adrp x8, :got:bar
+ ldr x8, [x8, :got_lo12:bar]
+ ret
+
+// CHECK: Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_RELA
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 72
+
+// CHECK: 0x0000000000000008 RELASZ 72
+// CHECK: 0x0000000000000002 PLTRELSZ 48
diff --git a/test/ELF/aarch64-combined-dynrel.s b/test/ELF/aarch64-combined-dynrel.s
new file mode 100644
index 000000000000..438c2509906e
--- /dev/null
+++ b/test/ELF/aarch64-combined-dynrel.s
@@ -0,0 +1,41 @@
+// REQUIRES: AArch64
+// RUN: llvm-mc --triple=aarch64-linux-gnu -filetype=obj -o %t.o %s
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
+// RUN: } " > %t.script
+// RUN: ld.lld %t.o -o %t.so --shared --script %t.script
+// RUN: llvm-readobj --section-headers --dynamic-table %t.so | FileCheck %s
+
+// The linker script above combines the .rela.dyn and .rela.plt into a single
+// table. ELF is clear that the DT_PLTRELSZ should match the subset of
+// relocations that is associated with the PLT. It is less clear about what
+// the value of DT_RELASZ should be. ELF implies that it should be the size
+// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
+// glibc permits this as long as .rela.plt comes after .rela.dyn in the
+// combined table.
+ .text
+ .globl func
+ .type func, %function
+ .globl foo
+ .type foo, %object
+
+ .globl _start
+ .type _start, %function
+_start:
+ bl func
+ adrp x8, :got:foo
+ ldr x8, [x8, :got_lo12:foo]
+ ret
+
+// CHECK: Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_RELA
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+
+// CHECK: 0x0000000000000008 RELASZ 48
+// CHECK: 0x0000000000000002 PLTRELSZ 24
diff --git a/test/ELF/aarch64-condb-reloc.s b/test/ELF/aarch64-condb-reloc.s
index 8a7581480544..b7fe7779def0 100644
--- a/test/ELF/aarch64-condb-reloc.s
+++ b/test/ELF/aarch64-condb-reloc.s
@@ -12,21 +12,21 @@
# 0x1102c - 16 = 0x1101c
# CHECK: Disassembly of section .text:
# CHECK-NEXT: _foo:
-# CHECK-NEXT: 20000: {{.*}} nop
-# CHECK-NEXT: 20004: {{.*}} nop
-# CHECK-NEXT: 20008: {{.*}} nop
-# CHECK-NEXT: 2000c: {{.*}} nop
+# CHECK-NEXT: 210000: {{.*}} nop
+# CHECK-NEXT: 210004: {{.*}} nop
+# CHECK-NEXT: 210008: {{.*}} nop
+# CHECK-NEXT: 21000c: {{.*}} nop
# CHECK: _bar:
-# CHECK-NEXT: 20010: {{.*}} nop
-# CHECK-NEXT: 20014: {{.*}} nop
-# CHECK-NEXT: 20018: {{.*}} nop
+# CHECK-NEXT: 210010: {{.*}} nop
+# CHECK-NEXT: 210014: {{.*}} nop
+# CHECK-NEXT: 210018: {{.*}} nop
# CHECK: _dah:
-# CHECK-NEXT: 2001c: {{.*}} nop
-# CHECK-NEXT: 20020: {{.*}} nop
+# CHECK-NEXT: 21001c: {{.*}} nop
+# CHECK-NEXT: 210020: {{.*}} nop
# CHECK: _start:
-# CHECK-NEXT: 20024: {{.*}} b.eq #-36
-# CHECK-NEXT: 20028: {{.*}} b.eq #-24
-# CHECK-NEXT: 2002c: {{.*}} b.eq #-16
+# CHECK-NEXT: 210024: {{.*}} b.eq #-36
+# CHECK-NEXT: 210028: {{.*}} b.eq #-24
+# CHECK-NEXT: 21002c: {{.*}} b.eq #-16
#DSOREL: Section {
#DSOREL: Index:
@@ -79,14 +79,20 @@
#DSO-NEXT: 10044: {{.*}} nop
#DSO-NEXT: 10048: {{.*}} nop
#DSO-NEXT: 1004c: {{.*}} nop
+#DSO-EMPTY:
+#DSO-NEXT: _foo@plt:
#DSO-NEXT: 10050: {{.*}} adrp x16, #65536
#DSO-NEXT: 10054: {{.*}} ldr x17, [x16, #24]
#DSO-NEXT: 10058: {{.*}} add x16, x16, #24
#DSO-NEXT: 1005c: {{.*}} br x17
+#DSO-EMPTY:
+#DSO-NEXT: _bar@plt:
#DSO-NEXT: 10060: {{.*}} adrp x16, #65536
#DSO-NEXT: 10064: {{.*}} ldr x17, [x16, #32]
#DSO-NEXT: 10068: {{.*}} add x16, x16, #32
#DSO-NEXT: 1006c: {{.*}} br x17
+#DSO-EMPTY:
+#DSO-NEXT: _dah@plt:
#DSO-NEXT: 10070: {{.*}} adrp x16, #65536
#DSO-NEXT: 10074: {{.*}} ldr x17, [x16, #40]
#DSO-NEXT: 10078: {{.*}} add x16, x16, #40
diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s
index 32e1c76df771..5a42c8db4796 100644
--- a/test/ELF/aarch64-copy.s
+++ b/test/ELF/aarch64-copy.s
@@ -22,7 +22,7 @@ _start:
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x40000
+// CHECK-NEXT: Address: 0x230000
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 24
// CHECK-NEXT: Link:
@@ -32,19 +32,19 @@ _start:
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
// CHECK-NEXT: Relocation {
-// CHECK-NEXT: Offset: 0x40000
+// CHECK-NEXT: Offset: 0x230000
// CHECK-NEXT: Type: R_AARCH64_COPY
// CHECK-NEXT: Symbol: x
// CHECK-NEXT: Addend: 0x0
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
-// CHECK-NEXT: Offset: 0x40010
+// CHECK-NEXT: Offset: 0x230010
// CHECK-NEXT: Type: R_AARCH64_COPY
// CHECK-NEXT: Symbol: y
// CHECK-NEXT: Addend: 0x0
// CHECK-NEXT: }
// CHECK-NEXT: Relocation {
-// CHECK-NEXT: Offset: 0x40014
+// CHECK-NEXT: Offset: 0x230014
// CHECK-NEXT: Type: R_AARCH64_COPY
// CHECK-NEXT: Symbol: z
// CHECK-NEXT: Addend: 0x0
@@ -54,21 +54,21 @@ _start:
// CHECK: Symbols [
// CHECK: Name: x
-// CHECK-NEXT: Value: 0x40000
+// CHECK-NEXT: Value: 0x230000
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Object
// CHECK-NEXT: Other:
// CHECK-NEXT: Section: .bss
// CHECK: Name: y
-// CHECK-NEXT: Value: 0x40010
+// CHECK-NEXT: Value: 0x230010
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Object
// CHECK-NEXT: Other:
// CHECK-NEXT: Section: .bss
// CHECK: Name: z
-// CHECK-NEXT: Value: 0x40014
+// CHECK-NEXT: Value: 0x230014
// CHECK-NEXT: Size: 4
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Object
@@ -78,16 +78,16 @@ _start:
// CODE: Disassembly of section .text:
// CODE-NEXT: _start:
-// S(x) = 0x40000, A = 0, P = 0x20000
+// S(x) = 0x230000, A = 0, P = 0x210000
// S + A - P = 0x20000 = 131072
-// CODE-NEXT: 20000: {{.*}} adr x1, #131072
-// S(y) = 0x40010, A = 0, P = 0x20004
-// Page(S + A) - Page(P) = 0x40000 - 0x20000 = 0x20000 = 131072
-// CODE-NEXT: 20004: {{.*}} adrp x2, #131072
-// S(y) = 0x40010, A = 0
+// CODE-NEXT: 210000: {{.*}} adr x1, #131072
+// S(y) = 0x230010, A = 0, P = 0x210004
+// Page(S + A) - Page(P) = 0x230000 - 0x210000 = 0x20000 = 131072
+// CODE-NEXT: 210004: {{.*}} adrp x2, #131072
+// S(y) = 0x230010, A = 0
// (S + A) & 0xFFF = 0x10 = 16
-// CODE-NEXT: 20008: {{.*}} add x2, x2, #16
+// CODE-NEXT: 210008: {{.*}} add x2, x2, #16
// RODATA: Contents of section .rodata:
-// S(z) = 0x40014
-// RODATA-NEXT: 102e0 14000400
+// S(z) = 0x230014
+// RODATA-NEXT: 2002e0 14002300
diff --git a/test/ELF/aarch64-copy2.s b/test/ELF/aarch64-copy2.s
index 6f72e21470ae..5324c74d47db 100644
--- a/test/ELF/aarch64-copy2.s
+++ b/test/ELF/aarch64-copy2.s
@@ -19,7 +19,7 @@ _start:
// CHECK-NEXT: Section: Undefined
// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x20030
+// CHECK-NEXT: Value: 0x210030
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Function
diff --git a/test/ELF/aarch64-cortex-a53-843419-abs-mapsyms.s b/test/ELF/aarch64-cortex-a53-843419-abs-mapsyms.s
new file mode 100644
index 000000000000..608b1aceb0a0
--- /dev/null
+++ b/test/ELF/aarch64-cortex-a53-843419-abs-mapsyms.s
@@ -0,0 +1,22 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t
+// RUN: ld.lld --just-symbols %t -fix-cortex-a53-843419 -o %t.axf
+// RUN: llvm-readobj --symbols %t.axf | FileCheck %s
+
+// Check that we can gracefully handle --just-symbols, which gives a local
+// absolute mapping symbol (with no Section). Previously we assumed that all
+// mapping symbols were defined relative to a section and assert failed.
+
+ .text
+ .global _start
+ .type _start, %function
+_start: ret
+
+// CHECK: Name: $x.0
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local (0x0)
+// CHECK-NEXT: Type: None (0x0)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Absolute (0xFFF1)
+// CHECK-NEXT: }
diff --git a/test/ELF/aarch64-cortex-a53-843419-cli.s b/test/ELF/aarch64-cortex-a53-843419-cli.s
index 9c1d4858b3a7..b19f6c3cd251 100644
--- a/test/ELF/aarch64-cortex-a53-843419-cli.s
+++ b/test/ELF/aarch64-cortex-a53-843419-cli.s
@@ -2,7 +2,7 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
// 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.
+// CHECK: --fix-cortex-a53-843419 is only supported on AArch64 targets
.globl entry
.text
.quad 0
diff --git a/test/ELF/aarch64-cortex-a53-843419-large.s b/test/ELF/aarch64-cortex-a53-843419-large.s
index 00c92ebeb182..c9021775337a 100644
--- a/test/ELF/aarch64-cortex-a53-843419-large.s
+++ b/test/ELF/aarch64-cortex-a53-843419-large.s
@@ -1,23 +1,23 @@
// REQUIRES: aarch64
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
// RUN: ld.lld --fix-cortex-a53-843419 %t.o -o %t2
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=131072 -stop-address=131084 | FileCheck --check-prefix=CHECK1 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=135168 -stop-address=135172 | FileCheck --check-prefix=CHECK2 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=139256 -stop-address=139272 | FileCheck --check-prefix=CHECK3 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=67256312 -stop-address=67256328 | FileCheck --check-prefix=CHECK4 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=100810760 -stop-address=100810776 | FileCheck --check-prefix=CHECK5 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=134352908 -stop-address=134352912 | FileCheck --check-prefix=CHECK6 %s
-// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=134356988 -stop-address=134357012 | FileCheck --check-prefix=CHECK7 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=2162688 -stop-address=2162700 | FileCheck --check-prefix=CHECK1 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=2166784 -stop-address=2166788 | FileCheck --check-prefix=CHECK2 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=2170872 -stop-address=2170888 | FileCheck --check-prefix=CHECK3 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=69287928 -stop-address=69287944 | FileCheck --check-prefix=CHECK4 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=102842376 -stop-address=102842392 | FileCheck --check-prefix=CHECK5 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=136384524 -stop-address=136384528 | FileCheck --check-prefix=CHECK6 %s
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 -start-address=136388604 -stop-address=136388628 | FileCheck --check-prefix=CHECK7 %s
// Test case for Cortex-A53 Erratum 843419 in an OutputSection exceeding
// the maximum branch range. Both range extension thunks and patches are
-// required.
-
+// required.
+
// CHECK1: __AArch64AbsLongThunk_need_thunk_after_patch:
-// CHECK1-NEXT: 20000: 50 00 00 58 ldr x16, #8
-// CHECK1-NEXT: 20004: 00 02 1f d6 br x16
-// CHECK1: $d:
-// CHECK1-NEXT: 20008: 0c 10 02 08 .word 0x0802100c
-
+// CHECK1-NEXT: 210000: 50 00 00 58 ldr x16, #8
+// CHECK1-NEXT: 210004: 00 02 1f d6 br x16
+// CHECK1: $d:
+// CHECK1-NEXT: 210008: 0c 10 21 08 .word 0x0821100c
+
.section .text.01, "ax", %progbits
.balign 4096
.globl _start
@@ -29,7 +29,7 @@ _start:
.space 4096 - 12
// CHECK2: _start:
-// CHECK2-NEXT: 21000: 00 fc ff 97 bl #-4096
+// CHECK2-NEXT: 211000: 00 fc ff 97 bl #-4096
// Expect patch on pass 1
.section .text.03, "ax", %progbits
@@ -42,10 +42,10 @@ t3_ff8_ldr:
ret
// CHECK3: t3_ff8_ldr:
-// CHECK3-NEXT: 21ff8: 60 00 04 f0 adrp x0, #134279168
-// CHECK3-NEXT: 21ffc: 21 00 40 f9 ldr x1, [x1]
-// CHECK3-NEXT: 22000: 02 08 80 15 b #100671496
-// CHECK3-NEXT: 22004: c0 03 5f d6 ret
+// CHECK3-NEXT: 211ff8: 60 00 04 f0 adrp x0, #134279168
+// CHECK3-NEXT: 211ffc: 21 00 40 f9 ldr x1, [x1]
+// CHECK3-NEXT: 212000: 02 08 80 15 b #100671496
+// CHECK3-NEXT: 212004: c0 03 5f d6 ret
.section .text.04, "ax", %progbits
.space 64 * 1024 * 1024
@@ -63,20 +63,20 @@ t3_ff8_str:
ret
// CHECK4: t3_ff8_str:
-// CHECK4-NEXT: 4023ff8: 60 00 02 b0 adrp x0, #67162112
-// CHECK4-NEXT: 4023ffc: 21 00 40 f9 ldr x1, [x1]
-// CHECK4-NEXT: 4024000: 04 00 80 14 b #33554448
-// CHECK4-NEXT: 4024004: c0 03 5f d6 ret
+// CHECK4-NEXT: 4213ff8: 60 00 02 b0 adrp x0, #67162112
+// CHECK4-NEXT: 4213ffc: 21 00 40 f9 ldr x1, [x1]
+// CHECK4-NEXT: 4214000: 04 00 80 14 b #33554448
+// CHECK4-NEXT: 4214004: c0 03 5f d6 ret
.section .text.06, "ax", %progbits
.space 32 * 1024 * 1024
-// CHECK5: __CortexA53843419_21000:
-// CHECK5-NEXT: 6024008: 00 00 40 f9 ldr x0, [x0]
-// CHECK5-NEXT: 602400c: fe f7 7f 16 b #-100671496
-// CHECK5: __CortexA53843419_4023000:
-// CHECK5-NEXT: 6024010: 00 00 00 f9 str x0, [x0]
-// CHECK5-NEXT: 6024014: fc ff 7f 17 b #-33554448
+// CHECK5: __CortexA53843419_211000:
+// CHECK5-NEXT: 6214008: 00 00 40 f9 ldr x0, [x0]
+// CHECK5-NEXT: 621400c: fe f7 7f 16 b #-100671496
+// CHECK5: __CortexA53843419_4213000:
+// CHECK5-NEXT: 6214010: 00 00 00 f9 str x0, [x0]
+// CHECK5-NEXT: 6214014: fc ff 7f 17 b #-33554448
.section .text.07, "ax", %progbits
.space (32 * 1024 * 1024) - 12300
@@ -88,7 +88,7 @@ need_thunk_after_patch:
ret
// CHECK6: need_thunk_after_patch:
-// CHECK6-NEXT: 802100c: c0 03 5f d6 ret
+// CHECK6-NEXT: 821100c: c0 03 5f d6 ret
// Will need a patch on pass 2
.section .text.09, "ax", %progbits
@@ -102,13 +102,13 @@ t3_ffc_ldr:
ret
// CHECK7: t3_ffc_ldr:
-// CHECK7-NEXT: 8021ffc: 60 00 00 f0 adrp x0, #61440
-// CHECK7-NEXT: 8022000: 21 00 40 f9 ldr x1, [x1]
-// CHECK7-NEXT: 8022004: 02 00 00 14 b #8
-// CHECK7-NEXT: 8022008: c0 03 5f d6 ret
-// CHECK7: __CortexA53843419_8022004:
-// CHECK7-NEXT: 802200c: 00 00 40 f9 ldr x0, [x0]
-// CHECK7-NEXT: 8022010: fe ff ff 17 b #-8
+// CHECK7-NEXT: 8211ffc: 60 00 00 f0 adrp x0, #61440
+// CHECK7-NEXT: 8212000: 21 00 40 f9 ldr x1, [x1]
+// CHECK7-NEXT: 8212004: 02 00 00 14 b #8
+// CHECK7-NEXT: 8212008: c0 03 5f d6 ret
+// CHECK7: __CortexA53843419_8212004:
+// CHECK7-NEXT: 821200c: 00 00 40 f9 ldr x0, [x0]
+// CHECK7-NEXT: 8212010: fe ff ff 17 b #-8
.section .data
.globl dat
diff --git a/test/ELF/aarch64-cortex-a53-843419-large2.s b/test/ELF/aarch64-cortex-a53-843419-large2.s
new file mode 100644
index 000000000000..fdb8a445e004
--- /dev/null
+++ b/test/ELF/aarch64-cortex-a53-843419-large2.s
@@ -0,0 +1,19 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+// RUN: ld.lld --fix-cortex-a53-843419 -Ttext=0x8000000 %t.o -o %t2
+// RUN: llvm-objdump -d --start-address=0x8001000 --stop-address=0x8001004 %t2 | FileCheck %s
+
+.section .text.01, "ax", %progbits
+.balign 4096
+.space 4096 - 8
+adrp x0, thunk
+ldr x1, [x1, #0]
+// CHECK: thunk:
+// CHECK-NEXT: b #67108872 <__CortexA53843419_8001000>
+thunk:
+ldr x0, [x0, :got_lo12:thunk]
+ret
+.space 64 * 1024 * 1024
+
+.section .text.02, "ax", %progbits
+.space 64 * 1024 * 1024
diff --git a/test/ELF/aarch64-cortex-a53-843419-recognize.s b/test/ELF/aarch64-cortex-a53-843419-recognize.s
index 174f18164bce..cde35919806e 100644
--- a/test/ELF/aarch64-cortex-a53-843419-recognize.s
+++ b/test/ELF/aarch64-cortex-a53-843419-recognize.s
@@ -26,13 +26,13 @@
// - Optional instruction 3 present or not.
// - Load or store for instruction 4.
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 211FF8 in unpatched output.
// 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 c8 00 14 b #204812
-// CHECK-NOFIX: 22000: 00 00 40 f9 ldr x0, [x0]
-// CHECK-NEXT: 22004: c0 03 5f d6 ret
+// CHECK-NEXT: 211ff8: e0 01 00 f0 adrp x0, #258048
+// CHECK-NEXT: 211ffc: 21 00 40 f9 ldr x1, [x1]
+// CHECK-FIX: 212000: 03 c8 00 14 b #204812
+// CHECK-NOFIX: 212000: 00 00 40 f9 ldr x0, [x0]
+// CHECK-NEXT: 212004: c0 03 5f d6 ret
.section .text.01, "ax", %progbits
.balign 4096
.globl t3_ff8_ldr
@@ -44,13 +44,13 @@ t3_ff8_ldr:
ldr x0, [x0, :got_lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 213FF8 in unpatched output.
// 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 c0 00 14 b #196628
-// CHECK-NOFIX: 24000: 02 04 40 f9 ldr x2, [x0, #8]
-// CHECK-NEXT: 24004: c0 03 5f d6 ret
+// CHECK-NEXT: 213ff8: e0 01 00 b0 adrp x0, #249856
+// CHECK-NEXT: 213ffc: 21 00 40 bd ldr s1, [x1]
+// CHECK-FIX: 214000: 05 c0 00 14 b #196628
+// CHECK-NOFIX: 214000: 02 04 40 f9 ldr x2, [x0, #8]
+// CHECK-NEXT: 214004: c0 03 5f d6 ret
.section .text.02, "ax", %progbits
.balign 4096
.globl t3_ff8_ldrsimd
@@ -62,13 +62,13 @@ t3_ff8_ldrsimd:
ldr x2, [x0, :got_lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 25FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 215FFC in unpatched output.
// 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 b8 00 14 b #188440
-// CHECK-NOFIX: 26004: 03 08 40 f9 ldr x3, [x0, #16]
-// CHECK-NEXT: 26008: c0 03 5f d6 ret
+// CHECK-NEXT: 215ffc: c0 01 00 f0 adrp x0, #241664
+// CHECK-NEXT: 216000: 21 84 40 bc ldr s1, [x1], #8
+// CHECK-FIX: 216004: 06 b8 00 14 b #188440
+// CHECK-NOFIX: 216004: 03 08 40 f9 ldr x3, [x0, #16]
+// CHECK-NEXT: 216008: c0 03 5f d6 ret
.section .text.03, "ax", %progbits
.balign 4096
.globl t3_ffc_ldrpost
@@ -80,13 +80,13 @@ t3_ffc_ldrpost:
ldr x3, [x0, :got_lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 27FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 217FF8 in unpatched output.
// 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 b0 00 14 b #180260
-// CHECK-NOFIX: 28000: 02 00 40 f9 ldr x2, [x0]
-// CHECK-NEXT: 28004: c0 03 5f d6 ret
+// CHECK-NEXT: 217ff8: c0 01 00 b0 adrp x0, #233472
+// CHECK-NEXT: 217ffc: 21 8c 00 bc str s1, [x1, #8]!
+// CHECK-FIX: 218000: 09 b0 00 14 b #180260
+// CHECK-NOFIX: 218000: 02 00 40 f9 ldr x2, [x0]
+// CHECK-NEXT: 218004: c0 03 5f d6 ret
.section .text.04, "ax", %progbits
.balign 4096
.globl t3_ff8_strpre
@@ -98,13 +98,13 @@ t3_ff8_strpre:
ldr x2, [x0, :lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 29FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 219FFC in unpatched output.
// 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 a8 00 14 b #172072
-// CHECK-NOFIX: 2a004: 9c 07 00 f9 str x28, [x28, #8]
-// CHECK-NEXT: 2a008: c0 03 5f d6 ret
+// CHECK-NEXT: 219ffc: bc 01 00 f0 adrp x28, #225280
+// CHECK-NEXT: 21a000: 42 00 00 f9 str x2, [x2]
+// CHECK-FIX: 21a004: 0a a8 00 14 b #172072
+// CHECK-NOFIX: 21a004: 9c 07 00 f9 str x28, [x28, #8]
+// CHECK-NEXT: 21a008: c0 03 5f d6 ret
.section .text.05, "ax", %progbits
.balign 4096
.globl t3_ffc_str
@@ -116,13 +116,13 @@ t3_ffc_str:
str x28, [x28, :lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 2BFFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21BFFC in unpatched output.
// 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 a0 00 14 b #163888
-// CHECK-NOFIX: 2c004: 84 0b 00 f9 str x4, [x28, #16]
-// CHECK-NEXT: 2c008: c0 03 5f d6 ret
+// CHECK-NEXT: 21bffc: bc 01 00 b0 adrp x28, #217088
+// CHECK-NEXT: 21c000: 44 00 00 b9 str w4, [x2]
+// CHECK-FIX: 21c004: 0c a0 00 14 b #163888
+// CHECK-NOFIX: 21c004: 84 0b 00 f9 str x4, [x28, #16]
+// CHECK-NEXT: 21c008: c0 03 5f d6 ret
.section .text.06, "ax", %progbits
.balign 4096
.globl t3_ffc_strsimd
@@ -134,13 +134,13 @@ t3_ffc_strsimd:
str x4, [x28, :lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 2DFF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21DFF8 in unpatched output.
// 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 98 00 14 b #155708
-// CHECK-NOFIX: 2e000: bd 03 40 f9 ldr x29, [x29]
-// CHECK-NEXT: 2e004: c0 03 5f d6 ret
+// CHECK-NEXT: 21dff8: 9d 01 00 f0 adrp x29, #208896
+// CHECK-NEXT: 21dffc: 41 08 40 38 ldtrb w1, [x2]
+// CHECK-FIX: 21e000: 0f 98 00 14 b #155708
+// CHECK-NOFIX: 21e000: bd 03 40 f9 ldr x29, [x29]
+// CHECK-NEXT: 21e004: c0 03 5f d6 ret
.section .text.07, "ax", %progbits
.balign 4096
.globl t3_ff8_ldrunpriv
@@ -152,13 +152,13 @@ t3_ff8_ldrunpriv:
ldr x29, [x29, :got_lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 2FFFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 21FFFC in unpatched output.
// 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 90 00 14 b #147520
-// CHECK-NOFIX: 30004: bd 07 40 f9 ldr x29, [x29, #8]
-// CHECK-NEXT: 30008: c0 03 5f d6 ret
+// CHECK-NEXT: 21fffc: 9d 01 00 b0 adrp x29, #200704
+// CHECK-NEXT: 220000: 42 40 40 b8 ldur w2, [x2, #4]
+// CHECK-FIX: 220004: 10 90 00 14 b #147520
+// CHECK-NOFIX: 220004: bd 07 40 f9 ldr x29, [x29, #8]
+// CHECK-NEXT: 220008: c0 03 5f d6 ret
.balign 4096
.globl t3_ffc_ldur
.type t3_ffc_ldur, %function
@@ -169,13 +169,13 @@ t3_ffc_ldur:
ldr x29, [x29, :got_lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 31FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 221FFC in unpatched output.
// 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 88 00 14 b #139336
-// CHECK-NOFIX: 32004: 41 0a 40 f9 ldr x1, [x18, #16]
-// CHECK-NEXT: 32008: c0 03 5f d6 ret
+// CHECK-NEXT: 221ffc: 72 01 00 f0 adrp x18, #192512
+// CHECK-NEXT: 222000: 43 40 00 78 sturh w3, [x2, #4]
+// CHECK-FIX: 222004: 12 88 00 14 b #139336
+// CHECK-NOFIX: 222004: 41 0a 40 f9 ldr x1, [x18, #16]
+// CHECK-NEXT: 222008: c0 03 5f d6 ret
.section .text.09, "ax", %progbits
.balign 4096
.globl t3_ffc_sturh
@@ -187,13 +187,13 @@ t3_ffc_sturh:
ldr x1, [x18, :got_lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 33FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 223FF8 in unpatched output.
// 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 80 00 14 b #131156
-// CHECK-NOFIX: 34000: 52 02 40 f9 ldr x18, [x18]
-// CHECK-NEXT: 34004: c0 03 5f d6 ret
+// CHECK-NEXT: 223ff8: 72 01 00 b0 adrp x18, #184320
+// CHECK-NEXT: 223ffc: e3 ff ff 58 ldr x3, #-4
+// CHECK-FIX: 224000: 15 80 00 14 b #131156
+// CHECK-NOFIX: 224000: 52 02 40 f9 ldr x18, [x18]
+// CHECK-NEXT: 224004: c0 03 5f d6 ret
.section .text.10, "ax", %progbits
.balign 4096
.globl t3_ff8_literal
@@ -205,13 +205,13 @@ t3_ff8_literal:
ldr x18, [x18, :lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 35FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 225FFC in unpatched output.
// 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 78 00 14 b #122968
-// CHECK-NOFIX: 36004: ea 05 40 f9 ldr x10, [x15, #8]
-// CHECK-NEXT: 36008: c0 03 5f d6 ret
+// CHECK-NEXT: 225ffc: 4f 01 00 f0 adrp x15, #176128
+// CHECK-NEXT: 226000: 43 68 61 f8 ldr x3, [x2, x1]
+// CHECK-FIX: 226004: 16 78 00 14 b #122968
+// CHECK-NOFIX: 226004: ea 05 40 f9 ldr x10, [x15, #8]
+// CHECK-NEXT: 226008: c0 03 5f d6 ret
.section .text.11, "ax", %progbits
.balign 4096
.globl t3_ffc_register
@@ -223,13 +223,13 @@ t3_ffc_register:
ldr x10, [x15, :lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 37FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 227FF8 in unpatched output.
// 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 70 00 14 b #114788
-// CHECK-NOFIX: 38000: 0d 0a 40 f9 ldr x13, [x16, #16]
-// CHECK-NEXT: 38004: c0 03 5f d6 ret
+// CHECK-NEXT: 227ff8: 50 01 00 b0 adrp x16, #167936
+// CHECK-NEXT: 227ffc: 61 08 00 a9 stp x1, x2, [x3]
+// CHECK-FIX: 228000: 19 70 00 14 b #114788
+// CHECK-NOFIX: 228000: 0d 0a 40 f9 ldr x13, [x16, #16]
+// CHECK-NEXT: 228004: c0 03 5f d6 ret
.section .text.12, "ax", %progbits
.balign 4096
.globl t3_ff8_stp
@@ -241,13 +241,13 @@ t3_ff8_stp:
ldr x13, [x16, :lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 39FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 229FFC in unpatched output.
// 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 68 00 14 b #106600
-// CHECK-NOFIX: 3a004: e9 00 40 f9 ldr x9, [x7]
-// CHECK-NEXT: 3a008: c0 03 5f d6 ret
+// CHECK-NEXT: 229ffc: 27 01 00 f0 adrp x7, #159744
+// CHECK-NEXT: 22a000: 61 08 00 a8 stnp x1, x2, [x3]
+// CHECK-FIX: 22a004: 1a 68 00 14 b #106600
+// CHECK-NOFIX: 22a004: e9 00 40 f9 ldr x9, [x7]
+// CHECK-NEXT: 22a008: c0 03 5f d6 ret
.section .text.13, "ax", %progbits
.balign 4096
.globl t3_ffc_stnp
@@ -259,13 +259,13 @@ t3_ffc_stnp:
ldr x9, [x7, :lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3BFFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22BFFC in unpatched output.
// CHECK: t3_ffc_st1singlepost:
-// CHECK-NEXT: 3bffc: 37 01 00 b0 adrp x23, #151552
-// 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
+// CHECK-NEXT: 22bffc: 37 01 00 b0 adrp x23, #151552
+// CHECK-NEXT: 22c000: 20 04 82 0d st1 { v0.b }[1], [x1], x2
+// CHECK-FIX: 22c004: 1c 60 00 14 b #98416
+// CHECK-NOFIX: 22c004: f6 06 40 f9 ldr x22, [x23, #8]
+// CHECK-NEXT: 22c008: c0 03 5f d6 ret
.section .text.14, "ax", %progbits
.balign 4096
.globl t3_ffc_st1singlepost
@@ -277,13 +277,13 @@ t3_ffc_st1singlepost:
ldr x22, [x23, :lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3DFF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22DFF8 in unpatched output.
// 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 58 00 14 b #90236
-// CHECK-NOFIX: 3e000: f8 0a 40 f9 ldr x24, [x23, #16]
-// CHECK-NEXT: 3e004: c0 03 5f d6 ret
+// CHECK-NEXT: 22dff8: 17 01 00 f0 adrp x23, #143360
+// CHECK-NEXT: 22dffc: 20 a0 00 4c st1 { v0.16b, v1.16b }, [x1]
+// CHECK-FIX: 22e000: 1f 58 00 14 b #90236
+// CHECK-NOFIX: 22e000: f8 0a 40 f9 ldr x24, [x23, #16]
+// CHECK-NEXT: 22e004: c0 03 5f d6 ret
.section .text.15, "ax", %progbits
.balign 4096
.globl t3_ff8_st1multiple
@@ -295,14 +295,14 @@ t3_ff8_st1multiple:
ldr x24, [x23, :lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3FFF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 22FFF8 in unpatched output.
// CHECK: t4_ff8_ldr:
-// 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 50 00 14 b #82048
-// CHECK-NOFIX: 40004: 02 00 40 f9 ldr x2, [x0]
-// CHECK-NEXT: 40008: c0 03 5f d6 ret
+// CHECK-NEXT: 22fff8: 00 01 00 b0 adrp x0, #135168
+// CHECK-NEXT: 22fffc: 21 00 40 f9 ldr x1, [x1]
+// CHECK-NEXT: 230000: 42 00 00 8b add x2, x2, x0
+// CHECK-FIX: 230004: 20 50 00 14 b #82048
+// CHECK-NOFIX: 230004: 02 00 40 f9 ldr x2, [x0]
+// CHECK-NEXT: 230008: c0 03 5f d6 ret
.section .text.16, "ax", %progbits
.balign 4096
.globl t4_ff8_ldr
@@ -315,14 +315,14 @@ t4_ff8_ldr:
ldr x2, [x0, :got_lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 41FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 231FFC in unpatched output.
// CHECK: t4_ffc_str:
-// 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 48 00 14 b #73860
-// CHECK-NOFIX: 42008: 9b 07 00 f9 str x27, [x28, #8]
-// CHECK-NEXT: 4200c: c0 03 5f d6 ret
+// CHECK-NEXT: 231ffc: fc 00 00 f0 adrp x28, #126976
+// CHECK-NEXT: 232000: 42 00 00 f9 str x2, [x2]
+// CHECK-NEXT: 232004: 20 00 02 cb sub x0, x1, x2
+// CHECK-FIX: 232008: 21 48 00 14 b #73860
+// CHECK-NOFIX: 232008: 9b 07 00 f9 str x27, [x28, #8]
+// CHECK-NEXT: 23200c: c0 03 5f d6 ret
.section .text.17, "ax", %progbits
.balign 4096
.globl t4_ffc_str
@@ -335,14 +335,14 @@ t4_ffc_str:
str x27, [x28, :got_lo12:dat2]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 43FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 233FF8 in unpatched output.
// CHECK: t4_ff8_stp:
-// 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 40 00 14 b #65680
-// CHECK-NOFIX: 44004: 0e 0a 40 f9 ldr x14, [x16, #16]
-// CHECK-NEXT: 44008: c0 03 5f d6 ret
+// CHECK-NEXT: 233ff8: f0 00 00 b0 adrp x16, #118784
+// CHECK-NEXT: 233ffc: 61 08 00 a9 stp x1, x2, [x3]
+// CHECK-NEXT: 234000: 03 7e 10 9b mul x3, x16, x16
+// CHECK-FIX: 234004: 24 40 00 14 b #65680
+// CHECK-NOFIX: 234004: 0e 0a 40 f9 ldr x14, [x16, #16]
+// CHECK-NEXT: 234008: c0 03 5f d6 ret
.section .text.18, "ax", %progbits
.balign 4096
.globl t4_ff8_stp
@@ -355,14 +355,14 @@ t4_ff8_stp:
ldr x14, [x16, :got_lo12:dat3]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 45FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 235FF8 in unpatched output.
// CHECK: t4_ff8_stppre:
-// 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 38 00 14 b #57496
-// CHECK-NOFIX: 46004: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-NEXT: 46008: c0 03 5f d6 ret
+// CHECK-NEXT: 235ff8: d0 00 00 f0 adrp x16, #110592
+// CHECK-NEXT: 235ffc: 61 08 81 a9 stp x1, x2, [x3, #16]!
+// CHECK-NEXT: 236000: 03 7e 10 9b mul x3, x16, x16
+// CHECK-FIX: 236004: 26 38 00 14 b #57496
+// CHECK-NOFIX: 236004: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-NEXT: 236008: c0 03 5f d6 ret
.section .text.19, "ax", %progbits
.balign 4096
.globl t4_ff8_stppre
@@ -375,14 +375,14 @@ t4_ff8_stppre:
ldr x14, [x16, #8]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 47FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 237FF8 in unpatched output.
// CHECK: t4_ff8_stppost:
-// 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 30 00 14 b #49312
-// CHECK-NOFIX: 48004: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-NEXT: 48008: c0 03 5f d6 ret
+// CHECK-NEXT: 237ff8: d0 00 00 b0 adrp x16, #102400
+// CHECK-NEXT: 237ffc: 61 08 81 a8 stp x1, x2, [x3], #16
+// CHECK-NEXT: 238000: 03 7e 10 9b mul x3, x16, x16
+// CHECK-FIX: 238004: 28 30 00 14 b #49312
+// CHECK-NOFIX: 238004: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-NEXT: 238008: c0 03 5f d6 ret
.section .text.20, "ax", %progbits
.balign 4096
.globl t4_ff8_stppost
@@ -395,14 +395,14 @@ t4_ff8_stppost:
ldr x14, [x16, #8]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 49FFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 239FFC in unpatched output.
// CHECK: t4_ffc_stpsimd:
-// 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 28 00 14 b #41124
-// CHECK-NOFIX: 4a008: 0e 06 40 f9 ldr x14, [x16, #8]
-// CHECK-NEXT: 4a00c: c0 03 5f d6 ret
+// CHECK-NEXT: 239ffc: b0 00 00 f0 adrp x16, #94208
+// CHECK-NEXT: 23a000: 61 08 00 ad stp q1, q2, [x3]
+// CHECK-NEXT: 23a004: 03 7e 10 9b mul x3, x16, x16
+// CHECK-FIX: 23a008: 29 28 00 14 b #41124
+// CHECK-NOFIX: 23a008: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-NEXT: 23a00c: c0 03 5f d6 ret
.section .text.21, "ax", %progbits
.balign 4096
.globl t4_ffc_stpsimd
@@ -415,14 +415,14 @@ t4_ffc_stpsimd:
ldr x14, [x16, #8]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4BFFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23BFFC in unpatched output.
// CHECK: t4_ffc_stnp:
-// 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 20 00 14 b #32940
-// CHECK-NOFIX: 4c008: ea 00 40 f9 ldr x10, [x7]
-// CHECK-NEXT: 4c00c: c0 03 5f d6 ret
+// CHECK-NEXT: 23bffc: a7 00 00 b0 adrp x7, #86016
+// CHECK-NEXT: 23c000: 61 08 00 a8 stnp x1, x2, [x3]
+// CHECK-NEXT: 23c004: 1f 20 03 d5 nop
+// CHECK-FIX: 23c008: 2b 20 00 14 b #32940
+// CHECK-NOFIX: 23c008: ea 00 40 f9 ldr x10, [x7]
+// CHECK-NEXT: 23c00c: c0 03 5f d6 ret
.section .text.22, "ax", %progbits
.balign 4096
.globl t4_ffc_stnp
@@ -435,14 +435,14 @@ t4_ffc_stnp:
ldr x10, [x7, :got_lo12:dat1]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4DFFC in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23DFFC in unpatched output.
// CHECK: t4_ffc_st1:
-// CHECK-NEXT: 4dffc: 98 00 00 f0 adrp x24, #77824
-// 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 18 00 14 b #24756
-// CHECK-NOFIX: 4e008: 18 ff 3f f9 str x24, [x24, #32760]
-// CHECK-NEXT: 4e00c: c0 03 5f d6 ret
+// CHECK-NEXT: 23dffc: 98 00 00 f0 adrp x24, #77824
+// CHECK-NEXT: 23e000: 20 80 00 4d st1 { v0.s }[2], [x1]
+// CHECK-NEXT: 23e004: f6 06 40 f9 ldr x22, [x23, #8]
+// CHECK-FIX: 23e008: 2d 18 00 14 b #24756
+// CHECK-NOFIX: 23e008: 18 ff 3f f9 str x24, [x24, #32760]
+// CHECK-NEXT: 23e00c: c0 03 5f d6 ret
.section .text.23, "ax", %progbits
.balign 4096
.globl t4_ffc_st1
@@ -455,14 +455,14 @@ t4_ffc_st1:
str x24, [x24, #32760]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4FFF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 23FFF8 in unpatched output.
// 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 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
+// CHECK-NEXT: 23fff8: 80 00 00 b0 adrp x0, #69632
+// CHECK-NEXT: 23fffc: 20 70 82 4c st1 { v0.16b }, [x1], x2
+// CHECK-FIX: 240000: 31 10 00 14 b #16580
+// CHECK-NOFIX: 240000: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-NEXT: 240004: 02 08 40 f9 ldr x2, [x0, #16]
+// CHECK-NEXT: 240008: c0 03 5f d6 ret
.section .text.24, "ax", %progbits
.balign 4096
.globl t3_ff8_ldr_once
@@ -475,14 +475,14 @@ t3_ff8_ldr_once:
ldr x2, [x0, #16]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 51FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 241FF8 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
+// CHECK-NEXT: 241ff8: 60 00 00 f0 adrp x0, #61440
+// CHECK-NEXT: 241ffc: 03 7c 5f c8 ldxr x3, [x0]
+// CHECK-FIX: 242000: 33 08 00 14 b #8396
+// CHECK-NOFIX: 242000: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK: 242004: 02 08 40 f9 ldr x2, [x0, #16]
+// CHECK-NEXT: 242008: c0 03 5f d6 ret
.section .text.25, "ax", %progbits
.balign 4096
.globl t3_ff8_ldxr
@@ -495,14 +495,14 @@ t3_ff8_ldxr:
ldr x2, [x0, #16]
ret
-// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 53FF8 in unpatched output.
+// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 243FF8 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
+// CHECK-NEXT: 243ff8: 60 00 00 b0 adrp x0, #53248
+// CHECK-NEXT: 243ffc: 03 7c 04 c8 stxr w4, x3, [x0]
+// CHECK-FIX: 244000: 35 00 00 14 b #212
+// CHECK-NOFIX: 244000: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK: 244004: 02 08 40 f9 ldr x2, [x0, #16]
+// CHECK-NEXT: 244008: c0 03 5f d6 ret
.section .text.26, "ax", %progbits
.balign 4096
.globl t3_ff8_stxr
@@ -521,84 +521,84 @@ t3_ff8_stxr:
_start:
ret
-// CHECK-FIX: __CortexA53843419_22000:
-// 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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
+// CHECK-FIX: __CortexA53843419_212000:
+// CHECK-FIX-NEXT: 24400c: 00 00 40 f9 ldr x0, [x0]
+// CHECK-FIX-NEXT: 244010: fd 37 ff 17 b #-204812
+// CHECK-FIX: __CortexA53843419_214000:
+// CHECK-FIX-NEXT: 244014: 02 04 40 f9 ldr x2, [x0, #8]
+// CHECK-FIX-NEXT: 244018: fb 3f ff 17 b #-196628
+// CHECK-FIX: __CortexA53843419_216004:
+// CHECK-FIX-NEXT: 24401c: 03 08 40 f9 ldr x3, [x0, #16]
+// CHECK-FIX-NEXT: 244020: fa 47 ff 17 b #-188440
+// CHECK-FIX: __CortexA53843419_218000:
+// CHECK-FIX-NEXT: 244024: 02 00 40 f9 ldr x2, [x0]
+// CHECK-FIX-NEXT: 244028: f7 4f ff 17 b #-180260
+// CHECK-FIX: __CortexA53843419_21A004:
+// CHECK-FIX-NEXT: 24402c: 9c 07 00 f9 str x28, [x28, #8]
+// CHECK-FIX-NEXT: 244030: f6 57 ff 17 b #-172072
+// CHECK-FIX: __CortexA53843419_21C004:
+// CHECK-FIX-NEXT: 244034: 84 0b 00 f9 str x4, [x28, #16]
+// CHECK-FIX-NEXT: 244038: f4 5f ff 17 b #-163888
+// CHECK-FIX: __CortexA53843419_21E000:
+// CHECK-FIX-NEXT: 24403c: bd 03 40 f9 ldr x29, [x29]
+// CHECK-FIX-NEXT: 244040: f1 67 ff 17 b #-155708
+// CHECK-FIX: __CortexA53843419_220004:
+// CHECK-FIX-NEXT: 244044: bd 07 40 f9 ldr x29, [x29, #8]
+// CHECK-FIX-NEXT: 244048: f0 6f ff 17 b #-147520
+// CHECK-FIX: __CortexA53843419_222004:
+// CHECK-FIX-NEXT: 24404c: 41 0a 40 f9 ldr x1, [x18, #16]
+// CHECK-FIX-NEXT: 244050: ee 77 ff 17 b #-139336
+// CHECK-FIX: __CortexA53843419_224000:
+// CHECK-FIX-NEXT: 244054: 52 02 40 f9 ldr x18, [x18]
+// CHECK-FIX-NEXT: 244058: eb 7f ff 17 b #-131156
+// CHECK-FIX: __CortexA53843419_226004:
+// CHECK-FIX-NEXT: 24405c: ea 05 40 f9 ldr x10, [x15, #8]
+// CHECK-FIX-NEXT: 244060: ea 87 ff 17 b #-122968
+// CHECK-FIX: __CortexA53843419_228000:
+// CHECK-FIX-NEXT: 244064: 0d 0a 40 f9 ldr x13, [x16, #16]
+// CHECK-FIX-NEXT: 244068: e7 8f ff 17 b #-114788
+// CHECK-FIX: __CortexA53843419_22A004:
+// CHECK-FIX-NEXT: 24406c: e9 00 40 f9 ldr x9, [x7]
+// CHECK-FIX-NEXT: 244070: e6 97 ff 17 b #-106600
+// CHECK-FIX: __CortexA53843419_22C004:
+// CHECK-FIX-NEXT: 244074: f6 06 40 f9 ldr x22, [x23, #8]
+// CHECK-FIX-NEXT: 244078: e4 9f ff 17 b #-98416
+// CHECK-FIX: __CortexA53843419_22E000:
+// CHECK-FIX-NEXT: 24407c: f8 0a 40 f9 ldr x24, [x23, #16]
+// CHECK-FIX-NEXT: 244080: e1 a7 ff 17 b #-90236
+// CHECK-FIX: __CortexA53843419_230004:
+// CHECK-FIX-NEXT: 244084: 02 00 40 f9 ldr x2, [x0]
+// CHECK-FIX-NEXT: 244088: e0 af ff 17 b #-82048
+// CHECK-FIX: __CortexA53843419_232008:
+// CHECK-FIX-NEXT: 24408c: 9b 07 00 f9 str x27, [x28, #8]
+// CHECK-FIX-NEXT: 244090: df b7 ff 17 b #-73860
+// CHECK-FIX: __CortexA53843419_234004:
+// CHECK-FIX-NEXT: 244094: 0e 0a 40 f9 ldr x14, [x16, #16]
+// CHECK-FIX-NEXT: 244098: dc bf ff 17 b #-65680
+// CHECK-FIX: __CortexA53843419_236004:
+// CHECK-FIX-NEXT: 24409c: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 2440a0: da c7 ff 17 b #-57496
+// CHECK-FIX: __CortexA53843419_238004:
+// CHECK-FIX-NEXT: 2440a4: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 2440a8: d8 cf ff 17 b #-49312
+// CHECK-FIX: __CortexA53843419_23A008:
+// CHECK-FIX-NEXT: 2440ac: 0e 06 40 f9 ldr x14, [x16, #8]
+// CHECK-FIX-NEXT: 2440b0: d7 d7 ff 17 b #-41124
+// CHECK-FIX: __CortexA53843419_23C008:
+// CHECK-FIX-NEXT: 2440b4: ea 00 40 f9 ldr x10, [x7]
+// CHECK-FIX-NEXT: 2440b8: d5 df ff 17 b #-32940
+// CHECK-FIX: __CortexA53843419_23E008:
+// CHECK-FIX-NEXT: 2440bc: 18 ff 3f f9 str x24, [x24, #32760]
+// CHECK-FIX-NEXT: 2440c0: d3 e7 ff 17 b #-24756
+// CHECK-FIX: __CortexA53843419_240000:
+// CHECK-FIX-NEXT: 2440c4: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 2440c8: cf ef ff 17 b #-16580
+// CHECK-FIX: __CortexA53843419_242000:
+// CHECK-FIX-NEXT: 2440cc: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 2440d0: cd f7 ff 17 b #-8396
+// CHECK-FIX: __CortexA53843419_244000:
+// CHECK-FIX-NEXT: 2440d4: 01 08 40 f9 ldr x1, [x0, #16]
+// CHECK-FIX-NEXT: 2440d8: cb ff ff 17 b #-212
.data
.globl dat
.globl dat2
diff --git a/test/ELF/aarch64-cortex-a53-843419-tlsrelax.s b/test/ELF/aarch64-cortex-a53-843419-tlsrelax.s
new file mode 100644
index 000000000000..2db5c7e36bbc
--- /dev/null
+++ b/test/ELF/aarch64-cortex-a53-843419-tlsrelax.s
@@ -0,0 +1,38 @@
+// REQUIRES: aarch64
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
+// RUN: ld.lld -fix-cortex-a53-843419 %t.o -o %t2
+// RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s
+
+// The following code sequence is covered by the TLS IE to LE relaxation. It
+// transforms the ADRP, LDR to MOVZ, MOVK. The former can trigger a
+// cortex-a53-843419 patch, whereas the latter can not. As both
+// relaxation and patching transform instructions very late in the
+// link there is a possibility of them both being simultaneously
+// applied. In this case the relaxed sequence is immune from the erratum so we
+// prefer to keep it.
+ .text
+ .balign 4096
+ .space 4096 - 8
+ .globl _start
+ .type _start,@function
+_start:
+ mrs x1, tpidr_el0
+ adrp x0, :gottprel:v
+ ldr x1, [x0, #:gottprel_lo12:v]
+ adrp x0, :gottprel:v
+ ldr x1, [x0, #:gottprel_lo12:v]
+ ret
+
+// CHECK: _start:
+// CHECK-NEXT: 210ff8: 41 d0 3b d5 mrs x1, TPIDR_EL0
+// CHECK-NEXT: 210ffc: 00 00 a0 d2 movz x0, #0, lsl #16
+// CHECK-NEXT: 211000: 01 08 80 f2 movk x1, #64
+// CHECK-NEXT: 211004: 00 00 a0 d2 movz x0, #0, lsl #16
+// CHECK-NEXT: 211008: 01 08 80 f2 movk x1, #64
+// CHECK-NEXT: 21100c: c0 03 5f d6 ret
+
+ .type v,@object
+ .section .tbss,"awT",@nobits
+ .globl v
+v:
+ .word 0
diff --git a/test/ELF/aarch64-data-relocs.s b/test/ELF/aarch64-data-relocs.s
index d32871543bf6..c2769758c6e5 100644
--- a/test/ELF/aarch64-data-relocs.s
+++ b/test/ELF/aarch64-data-relocs.s
@@ -12,7 +12,7 @@ _start:
// S = 0x100, A = 0x24
// S + A = 0x124
// CHECK: Contents of section .R_AARCH64_ABS64:
-// CHECK-NEXT: 20000 24010000 00000000
+// CHECK-NEXT: 210000 24010000 00000000
.section .R_AARCH64_PREL64, "ax",@progbits
.xword foo - . + 0x24
@@ -20,4 +20,4 @@ _start:
// S = 0x100, A = 0x24, P = 0x20008
// S + A - P = 0xfffffffffffe011c
// CHECK: Contents of section .R_AARCH64_PREL64:
-// CHECK-NEXT: 20008 1c01feff ffffffff
+// CHECK-NEXT: 210008 1c01dfff ffffffff
diff --git a/test/ELF/aarch64-gnu-ifunc-address.s b/test/ELF/aarch64-gnu-ifunc-address.s
new file mode 100644
index 000000000000..9321fe35e536
--- /dev/null
+++ b/test/ELF/aarch64-gnu-ifunc-address.s
@@ -0,0 +1,40 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %tout
+# RUN: llvm-objdump -D %tout | FileCheck %s
+# RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=CHECK-RELOCS
+
+# Test that when we take the address of a preemptible ifunc in a shared object
+# we get R_AARCH64_GLOB_DAT to the symbol as it could be defined in another
+# link unit and preempt our definition.
+.text
+.globl myfunc
+.type myfunc,@gnu_indirect_function
+myfunc:
+ ret
+
+.text
+.globl main
+.type main,@function
+main:
+ adrp x8, :got:myfunc
+ ldr x8, [x8, :got_lo12:myfunc]
+ ret
+# CHECK: 0000000000010004 main:
+# x8 = 0x30000
+# CHECK-NEXT: 10004: 08 01 00 90 adrp x8, #131072
+# x8 = 0x300e0 = .got entry for myfunc with R_AARCH64_GLOB_DAT
+# CHECK-NEXT: 10008: 08 71 40 f9 ldr x8, [x8, #224]
+# CHECK-NEXT: 1000c: c0 03 5f d6 ret
+
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: 00000000000300e0 .got:
+
+# CHECK-RELOCS: Relocations [
+# CHECK-RELOCS-NEXT: Section {{.*}} .rela.dyn {
+# CHECK-RELOCS-NEXT: 0x300E0 R_AARCH64_GLOB_DAT myfunc 0x0
+# CHECK-RELOCS-NEXT: }
+# CHECK-RELOCS-NEXT: Section {{.*}} .rela.plt {
+# CHECK-RELOCS-NEXT: 0x20018 R_AARCH64_JUMP_SLOT myfunc 0x0
+# CHECK-RELOCS-NEXT: }
+# CHECK-RELOCS-NEXT: ]
diff --git a/test/ELF/aarch64-gnu-ifunc-plt.s b/test/ELF/aarch64-gnu-ifunc-plt.s
index ca30316c7afe..381bcf7cd142 100644
--- a/test/ELF/aarch64-gnu-ifunc-plt.s
+++ b/test/ELF/aarch64-gnu-ifunc-plt.s
@@ -10,19 +10,19 @@
// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
// CHECK: Relocations [
// CHECK-NEXT: Section (4) .rela.plt {
-// CHECK: 0x30018 R_AARCH64_JUMP_SLOT bar2 0x0
-// CHECK-NEXT: 0x30020 R_AARCH64_JUMP_SLOT zed2 0x0
-// CHECK-NEXT: 0x30028 R_AARCH64_IRELATIVE - 0x20000
-// CHECK-NEXT: 0x30030 R_AARCH64_IRELATIVE - 0x20004
+// CHECK: 0x220018 R_AARCH64_JUMP_SLOT bar2 0x0
+// CHECK-NEXT: 0x220020 R_AARCH64_JUMP_SLOT zed2 0x0
+// CHECK-NEXT: 0x220028 R_AARCH64_IRELATIVE - 0x210000
+// CHECK-NEXT: 0x220030 R_AARCH64_IRELATIVE - 0x210004
// CHECK-NEXT: }
// CHECK-NEXT: ]
// Check that .got.plt entries point back to PLT header
// GOTPLT: Contents of section .got.plt:
-// GOTPLT-NEXT: 30000 00000000 00000000 00000000 00000000
-// GOTPLT-NEXT: 30010 00000000 00000000 20000200 00000000
-// GOTPLT-NEXT: 30020 20000200 00000000 20000200 00000000
-// GOTPLT-NEXT: 30030 20000200 00000000
+// GOTPLT-NEXT: 220000 00000000 00000000 00000000 00000000
+// GOTPLT-NEXT: 220010 00000000 00000000 20002100 00000000
+// GOTPLT-NEXT: 220020 20002100 00000000 20002100 00000000
+// GOTPLT-NEXT: 220030 20002100 00000000
// Check that the PLTRELSZ tag includes the IRELATIVE relocations
// CHECK: DynamicSection [
@@ -31,40 +31,44 @@
// Check that a PLT header is written and the ifunc entries appear last
// DISASM: Disassembly of section .text:
// DISASM-NEXT: foo:
-// DISASM-NEXT: 20000: {{.*}} ret
+// DISASM-NEXT: 210000: {{.*}} ret
// DISASM: bar:
-// DISASM-NEXT: 20004: {{.*}} ret
+// DISASM-NEXT: 210004: {{.*}} ret
// DISASM: _start:
-// DISASM-NEXT: 20008: {{.*}} bl #88
-// DISASM-NEXT: 2000c: {{.*}} bl #100
-// DISASM-NEXT: 20010: {{.*}} bl #48
-// DISASM-NEXT: 20014: {{.*}} bl #60
+// DISASM-NEXT: 210008: {{.*}} bl #88
+// DISASM-NEXT: 21000c: {{.*}} bl #100
+// DISASM-NEXT: 210010: {{.*}} bl #48
+// DISASM-NEXT: 210014: {{.*}} bl #60
// DISASM-NEXT: Disassembly of section .plt:
// DISASM-NEXT: .plt:
-// DISASM-NEXT: 20020: {{.*}} stp x16, x30, [sp, #-16]!
-// DISASM-NEXT: 20024: {{.*}} adrp x16, #65536
-// DISASM-NEXT: 20028: {{.*}} ldr x17, [x16, #16]
-// DISASM-NEXT: 2002c: {{.*}} add x16, x16, #16
-// DISASM-NEXT: 20030: {{.*}} br x17
-// DISASM-NEXT: 20034: {{.*}} nop
-// DISASM-NEXT: 20038: {{.*}} nop
-// DISASM-NEXT: 2003c: {{.*}} nop
-// DISASM-NEXT: 20040: {{.*}} adrp x16, #65536
-// DISASM-NEXT: 20044: {{.*}} ldr x17, [x16, #24]
-// DISASM-NEXT: 20048: {{.*}} add x16, x16, #24
-// DISASM-NEXT: 2004c: {{.*}} br x17
-// DISASM-NEXT: 20050: {{.*}} adrp x16, #65536
-// DISASM-NEXT: 20054: {{.*}} ldr x17, [x16, #32]
-// DISASM-NEXT: 20058: {{.*}} add x16, x16, #32
-// DISASM-NEXT: 2005c: {{.*}} br x17
-// DISASM-NEXT: 20060: {{.*}} adrp x16, #65536
-// DISASM-NEXT: 20064: {{.*}} ldr x17, [x16, #40]
-// DISASM-NEXT: 20068: {{.*}} add x16, x16, #40
-// DISASM-NEXT: 2006c: {{.*}} br x17
-// DISASM-NEXT: 20070: {{.*}} adrp x16, #65536
-// DISASM-NEXT: 20074: {{.*}} ldr x17, [x16, #48]
-// DISASM-NEXT: 20078: {{.*}} add x16, x16, #48
-// DISASM-NEXT: 2007c: {{.*}} br x17
+// DISASM-NEXT: 210020: {{.*}} stp x16, x30, [sp, #-16]!
+// DISASM-NEXT: 210024: {{.*}} adrp x16, #65536
+// DISASM-NEXT: 210028: {{.*}} ldr x17, [x16, #16]
+// DISASM-NEXT: 21002c: {{.*}} add x16, x16, #16
+// DISASM-NEXT: 210030: {{.*}} br x17
+// DISASM-NEXT: 210034: {{.*}} nop
+// DISASM-NEXT: 210038: {{.*}} nop
+// DISASM-NEXT: 21003c: {{.*}} nop
+// DISASM-EMPTY:
+// DISASM-NEXT: bar2@plt:
+// DISASM-NEXT: 210040: {{.*}} adrp x16, #65536
+// DISASM-NEXT: 210044: {{.*}} ldr x17, [x16, #24]
+// DISASM-NEXT: 210048: {{.*}} add x16, x16, #24
+// DISASM-NEXT: 21004c: {{.*}} br x17
+// DISASM-EMPTY:
+// DISASM-NEXT: zed2@plt:
+// DISASM-NEXT: 210050: {{.*}} adrp x16, #65536
+// DISASM-NEXT: 210054: {{.*}} ldr x17, [x16, #32]
+// DISASM-NEXT: 210058: {{.*}} add x16, x16, #32
+// DISASM-NEXT: 21005c: {{.*}} br x17
+// DISASM-NEXT: 210060: {{.*}} adrp x16, #65536
+// DISASM-NEXT: 210064: {{.*}} ldr x17, [x16, #40]
+// DISASM-NEXT: 210068: {{.*}} add x16, x16, #40
+// DISASM-NEXT: 21006c: {{.*}} br x17
+// DISASM-NEXT: 210070: {{.*}} adrp x16, #65536
+// DISASM-NEXT: 210074: {{.*}} ldr x17, [x16, #48]
+// DISASM-NEXT: 210078: {{.*}} add x16, x16, #48
+// DISASM-NEXT: 21007c: {{.*}} br x17
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/aarch64-gnu-ifunc.s b/test/ELF/aarch64-gnu-ifunc.s
index b3c1571b7604..9a15f1341d3d 100644
--- a/test/ELF/aarch64-gnu-ifunc.s
+++ b/test/ELF/aarch64-gnu-ifunc.s
@@ -16,14 +16,14 @@
// CHECK-NEXT: Offset: 0x158
// CHECK-NEXT: Size: 48
// CHECK-NEXT: Link: 0
-// CHECK-NEXT: Info: 0
+// CHECK-NEXT: Info: 4
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 24
// CHECK-NEXT: }
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.plt {
-// CHECK-NEXT: 0x30000 R_AARCH64_IRELATIVE
-// CHECK-NEXT: 0x30008 R_AARCH64_IRELATIVE
+// CHECK-NEXT: 0x220000 R_AARCH64_IRELATIVE
+// CHECK-NEXT: 0x220008 R_AARCH64_IRELATIVE
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK: Symbols [
@@ -38,7 +38,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: $x.0
-// CHECK-NEXT: Value: 0x20000
+// CHECK-NEXT: Value: 0x210000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
@@ -47,7 +47,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: __rela_iplt_end
-// CHECK-NEXT: Value: 0x10188
+// CHECK-NEXT: Value: 0x200188
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
@@ -58,7 +58,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: __rela_iplt_start
-// CHECK-NEXT: Value: 0x10158
+// CHECK-NEXT: Value: 0x200158
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
@@ -69,7 +69,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: _start
-// CHECK-NEXT: Value: 0x20008
+// CHECK-NEXT: Value: 0x210008
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: None
@@ -78,7 +78,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: bar
-// CHECK-NEXT: Value: 0x20004
+// CHECK-NEXT: Value: 0x210004
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: GNU_IFunc
@@ -87,7 +87,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: foo
-// CHECK-NEXT: Value: 0x20000
+// CHECK-NEXT: Value: 0x210000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: GNU_IFunc
@@ -101,24 +101,24 @@
// DISASM: Disassembly of section .text:
// DISASM-NEXT: foo:
-// DISASM-NEXT: 20000: c0 03 5f d6 ret
+// DISASM-NEXT: 210000: c0 03 5f d6 ret
// DISASM: bar:
-// DISASM-NEXT: 20004: c0 03 5f d6 ret
+// DISASM-NEXT: 210004: c0 03 5f d6 ret
// DISASM: _start:
-// DISASM-NEXT: 20008: 06 00 00 94 bl #24
-// DISASM-NEXT: 2000c: 09 00 00 94 bl #36
-// DISASM-NEXT: 20010: 42 60 05 91 add x2, x2, #344
-// DISASM-NEXT: 20014: 42 20 06 91 add x2, x2, #392
+// DISASM-NEXT: 210008: 06 00 00 94 bl #24
+// DISASM-NEXT: 21000c: 09 00 00 94 bl #36
+// DISASM-NEXT: 210010: 42 60 05 91 add x2, x2, #344
+// DISASM-NEXT: 210014: 42 20 06 91 add x2, x2, #392
// DISASM-NEXT: Disassembly of section .plt:
// DISASM-NEXT: .plt:
-// DISASM-NEXT: 20020: 90 00 00 90 adrp x16, #65536
-// DISASM-NEXT: 20024: 11 02 40 f9 ldr x17, [x16]
-// DISASM-NEXT: 20028: 10 02 00 91 add x16, x16, #0
-// DISASM-NEXT: 2002c: 20 02 1f d6 br x17
-// DISASM-NEXT: 20030: 90 00 00 90 adrp x16, #65536
-// DISASM-NEXT: 20034: 11 06 40 f9 ldr x17, [x16, #8]
-// DISASM-NEXT: 20038: 10 22 00 91 add x16, x16, #8
-// DISASM-NEXT: 2003c: 20 02 1f d6 br x17
+// DISASM-NEXT: 210020: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT: 210024: 11 02 40 f9 ldr x17, [x16]
+// DISASM-NEXT: 210028: 10 02 00 91 add x16, x16, #0
+// DISASM-NEXT: 21002c: 20 02 1f d6 br x17
+// DISASM-NEXT: 210030: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT: 210034: 11 06 40 f9 ldr x17, [x16, #8]
+// DISASM-NEXT: 210038: 10 22 00 91 add x16, x16, #8
+// DISASM-NEXT: 21003c: 20 02 1f d6 br x17
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/aarch64-gnu-ifunc2.s b/test/ELF/aarch64-gnu-ifunc2.s
new file mode 100644
index 000000000000..2caff3f14586
--- /dev/null
+++ b/test/ELF/aarch64-gnu-ifunc2.s
@@ -0,0 +1,52 @@
+# 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
+# RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: myfunc:
+# CHECK-NEXT: 210000:
+
+# CHECK: main:
+# adrp x8, 0x230000, 0x230000 == address in .got
+# CHECK-NEXT: 210004: {{.*}} adrp x8, #131072
+# CHECK-NEXT: 210008: {{.*}} ldr x8, [x8]
+# CHECK-NEXT: 21000c: {{.*}} ret
+
+# CHECK: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# adrp x16, 0x220000, 0x220000 == address in .got.plt
+# CHECK-NEXT: 210010: {{.*}} adrp x16, #65536
+# CHECK-NEXT: 210014: {{.*}} ldr x17, [x16]
+# CHECK-NEXT: 210018: {{.*}} add x16, x16, #0
+# CHECK-NEXT: 21001c: {{.*}} br x17
+
+# CHECK: Disassembly of section .got.plt:
+# CHECK-NEXT: .got.plt:
+# CHECK-NEXT: 220000:
+
+# CHECK: Disassembly of section .got:
+# CHECK-NEXT: .got:
+# 0x210010 == address in .plt
+# CHECK-NEXT: 230000: 10 00 21 00
+
+# RELOC: Relocations [
+# RELOC-NEXT: Section {{.*}} .rela.plt {
+# RELOC-NEXT: 0x220000 R_AARCH64_IRELATIVE - 0x210000
+# RELOC-NEXT: }
+# RELOC-NEXT: ]
+
+.text
+.globl myfunc
+.type myfunc,@gnu_indirect_function
+myfunc:
+ ret
+
+.text
+.globl main
+.type main,@function
+main:
+ adrp x8, :got:myfunc
+ ldr x8, [x8, :got_lo12:myfunc]
+ ret
diff --git a/test/ELF/aarch64-gnu-ifunc3.s b/test/ELF/aarch64-gnu-ifunc3.s
new file mode 100644
index 000000000000..11d5631b8578
--- /dev/null
+++ b/test/ELF/aarch64-gnu-ifunc3.s
@@ -0,0 +1,49 @@
+# 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
+# RUN: llvm-readobj -r %tout | FileCheck %s --check-prefix=RELOC
+
+# The address of myfunc is the address of the PLT entry for myfunc.
+# The adrp to myfunc should generate a PLT entry and a got entry with an
+# irelative relocation.
+.text
+.globl myfunc
+.type myfunc,@gnu_indirect_function
+myfunc:
+ ret
+
+.text
+.globl _start
+.type _start,@function
+_start:
+ adrp x8, myfunc
+ add x8, x8, :lo12:myfunc
+ ret
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT: myfunc:
+# CHECK-NEXT: 210000: c0 03 5f d6 ret
+# CHECK: _start:
+# adrp x8, 0x210000 + 0x10 from add == .plt entry
+# CHECK-NEXT: 210004: 08 00 00 90 adrp x8, #0
+# CHECK-NEXT: 210008: 08 41 00 91 add x8, x8, #16
+# CHECK-NEXT: 21000c: c0 03 5f d6 ret
+# CHECK-NEXT: Disassembly of section .plt:
+# CHECK-NEXT: .plt:
+# adrp x16, 0x220000, 0x220000 == address in .got.plt
+# CHECK-NEXT: 210010: 90 00 00 90 adrp x16, #65536
+# CHECK-NEXT: 210014: 11 02 40 f9 ldr x17, [x16]
+# CHECK-NEXT: 210018: 10 02 00 91 add x16, x16, #0
+# CHECK-NEXT: 21001c: 20 02 1f d6 br x17
+# CHECK-NEXT: Disassembly of section .got.plt:
+# CHECK-NEXT: .got.plt:
+# 0x210010 == address in .plt
+# CHECK-NEXT: 220000: 10 00 21 00
+# CHECK-NEXT: 220004: 00 00 00 00
+
+# RELOC: Relocations [
+# RELOC-NEXT: Section (1) .rela.plt {
+# RELOC-NEXT: 0x220000 R_AARCH64_IRELATIVE - 0x210000
+# RELOC-NEXT: }
+# RELOC-NEXT: ]
diff --git a/test/ELF/aarch64-jump26-thunk.s b/test/ELF/aarch64-jump26-thunk.s
index 13c084a0c78e..a381c701eca1 100644
--- a/test/ELF/aarch64-jump26-thunk.s
+++ b/test/ELF/aarch64-jump26-thunk.s
@@ -11,10 +11,10 @@ _start:
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
-// CHECK-NEXT: 20000: 02 00 00 14 b #8
+// CHECK-NEXT: 210000: 02 00 00 14 b #8
// CHECK: __AArch64AbsLongThunk_big:
-// CHECK-NEXT: 20008: 50 00 00 58 ldr x16, #8
-// CHECK-NEXT: 2000c: 00 02 1f d6 br x16
+// CHECK-NEXT: 210008: 50 00 00 58 ldr x16, #8
+// CHECK-NEXT: 21000c: 00 02 1f d6 br x16
// CHECK: $d:
-// CHECK-NEXT: 20010: 00 00 00 00 .word 0x00000000
-// CHECK-NEXT: 20014: 10 00 00 00 .word 0x00000010
+// CHECK-NEXT: 210010: 00 00 00 00 .word 0x00000000
+// CHECK-NEXT: 210014: 10 00 00 00 .word 0x00000010
diff --git a/test/ELF/aarch64-lo12-alignment.s b/test/ELF/aarch64-lo12-alignment.s
index 7edecd4494f5..a7ed99751490 100644
--- a/test/ELF/aarch64-lo12-alignment.s
+++ b/test/ELF/aarch64-lo12-alignment.s
@@ -39,7 +39,7 @@ foo4:
foo8:
.space 8
-// CHECK: improper alignment for relocation R_AARCH64_LDST16_ABS_LO12_NC: 0x30001 is not aligned to 2 bytes
-// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST32_ABS_LO12_NC: 0x30002 is not aligned to 4 bytes
-// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST64_ABS_LO12_NC: 0x30004 is not aligned to 8 bytes
-// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST128_ABS_LO12_NC: 0x30008 is not aligned to 16 bytes
+// CHECK: improper alignment for relocation R_AARCH64_LDST16_ABS_LO12_NC: 0x220001 is not aligned to 2 bytes
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST32_ABS_LO12_NC: 0x220002 is not aligned to 4 bytes
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST64_ABS_LO12_NC: 0x220004 is not aligned to 8 bytes
+// CHECK-NEXT: improper alignment for relocation R_AARCH64_LDST128_ABS_LO12_NC: 0x220008 is not aligned to 16 bytes
diff --git a/test/ELF/aarch64-prel16.s b/test/ELF/aarch64-prel16.s
index fc34f010853c..18a594c319a1 100644
--- a/test/ELF/aarch64-prel16.s
+++ b/test/ELF/aarch64-prel16.s
@@ -7,8 +7,8 @@
.globl _start
_start:
.data
- .hword foo - . + 0x20eff
- .hword foo - . + 0x8f02
+ .hword foo - . + 0x210eff
+ .hword foo - . + 0x1f8f02
// Note: If this test fails, it probably happens because of
// the change of the address of the .data section.
@@ -18,14 +18,14 @@ _start:
// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
// CHECK: Contents of section .data:
-// 11000: S = 0x100, A = 0x20eff, P = 0x11000
-// S + A - P = 0xffff
-// 11002: S = 0x100, A = 0x8f02, P = 0x11002
-// S + A - P = 0x8000
-// CHECK-NEXT: 11000 ffff0080
+// 201000: S = 0x100, A = 0x210eff, P = 0x201000
+// S + A - P = 0xffff
+// 201002: S = 0x100, A = 0x1f8f02, P = 0x201002
+// S + A - P = 0x8000
+// CHECK-NEXT: 201000 ffff0080
-// RUN: not ld.lld %t.o %t255.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// RUN: not ld.lld %t.o %t257.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// OVERFLOW: Relocation R_AARCH64_PREL16 out of range: -94209 is not in [-32768, 65535]
+// RUN: not ld.lld -z max-page-size=4096 %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1
+// OVERFLOW1: relocation R_AARCH64_PREL16 out of range: -32769 is not in [-32768, 32767]
+
+// RUN: not ld.lld -z max-page-size=4096 %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2
+// OVERFLOW2: relocation R_AARCH64_PREL16 out of range: 65536 is not in [-32768, 32767]
diff --git a/test/ELF/aarch64-prel32.s b/test/ELF/aarch64-prel32.s
index 7aa290382c53..16c8bb3c2019 100644
--- a/test/ELF/aarch64-prel32.s
+++ b/test/ELF/aarch64-prel32.s
@@ -7,8 +7,8 @@
.globl _start
_start:
.data
- .word foo - . + 0x100010eff
- .word foo - . - 0x7ffef0fc
+ .word foo - . + 0x100200eff
+ .word foo - . - 0x7fdff0fc
// Note: If this test fails, it probably happens because of
// the change of the address of the .data section.
@@ -18,14 +18,14 @@ _start:
// RUN: llvm-objdump -s -section=.data %t2 | FileCheck %s
// CHECK: Contents of section .data:
-// 11000: S = 0x100, A = 0x100010eff, P = 0x11000
-// S + A - P = 0xffffffff
-// 11004: S = 0x100, A = -0x7ffef0fc, P = 0x11004
-// S + A - P = 0x80000000
-// CHECK-NEXT: 11000 ffffffff 00000080
+// 201000: S = 0x100, A = 0x100200eff, P = 0x201000
+// S + A - P = 0xffffffff
+// 201004: S = 0x100, A = -0x7fdff0fc, P = 0x201004
+// S + A - P = 0x80000000
+// CHECK-NEXT: 201000 ffffffff 00000080
-// RUN: not ld.lld %t.o %t255.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// RUN: not ld.lld %t.o %t257.o -o %t2
-// | FileCheck %s --check-prefix=OVERFLOW
-// OVERFLOW: Relocation R_AARCH64_PREL32 out of range: 18446744071562006527 is not in [-2147483648, 4294967295]
+// RUN: not ld.lld -z max-page-size=4096 %t.o %t255.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW1
+// OVERFLOW1: relocation R_AARCH64_PREL32 out of range: -2147483649 is not in [-2147483648, 2147483647]
+
+// RUN: not ld.lld -z max-page-size=4096 %t.o %t257.o -o %t2 2>&1 | FileCheck %s --check-prefix=OVERFLOW2
+// OVERFLOW2: relocation R_AARCH64_PREL32 out of range: 4294967296 is not in [-2147483648, 2147483647]
diff --git a/test/ELF/aarch64-relocs.s b/test/ELF/aarch64-relocs.s
index 79caabcb6bb5..93a67c00c6ec 100644
--- a/test/ELF/aarch64-relocs.s
+++ b/test/ELF/aarch64-relocs.s
@@ -24,13 +24,13 @@ mystr:
.asciz "blah"
.size mystr, 4
-# S = 0x20012, A = 0x4, P = 0x20012
-# PAGE(S + A) = 0x11000
-# PAGE(P) = 0x11000
+# S = 0x210012, A = 0x4, P = 0x210012
+# PAGE(S + A) = 0x210000
+# PAGE(P) = 0x210000
#
# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_PG_H121:
# CHECK-NEXT: $x.2:
-# CHECK-NEXT: 20012: 01 00 00 90 adrp x1, #0
+# CHECK-NEXT: 210012: 01 00 00 90 adrp x1, #0
.section .R_AARCH64_ADD_ABS_LO12_NC,"ax",@progbits
add x0, x0, :lo12:.L.str
@@ -38,13 +38,13 @@ mystr:
.asciz "blah"
.size mystr, 4
-# S = 0x2001b, A = 0x4
+# S = 0x21001b, A = 0x4
# R = (S + A) & 0xFFF = 0x1f
# R << 10 = 0x7c00
#
# CHECK: Disassembly of section .R_AARCH64_ADD_ABS_LO12_NC:
# CHECK-NEXT: $x.4:
-# CHECK-NEXT: 2001b: 00 7c 00 91 add x0, x0, #31
+# CHECK-NEXT: 21001b: 00 7c 00 91 add x0, x0, #31
.section .R_AARCH64_LDST64_ABS_LO12_NC,"ax",@progbits
ldr x28, [x27, :lo12:foo]
@@ -52,12 +52,12 @@ foo:
.asciz "foo"
.size mystr, 3
-# S = 0x20024, A = 0x4
+# S = 0x210024, A = 0x4
# R = ((S + A) & 0xFFF) << 7 = 0x00001400
# 0x00001400 | 0xf940177c = 0xf940177c
# CHECK: Disassembly of section .R_AARCH64_LDST64_ABS_LO12_NC:
# CHECK-NEXT: $x.6:
-# CHECK-NEXT: 20024: 7c 17 40 f9 ldr x28, [x27, #40]
+# CHECK-NEXT: 210024: 7c 17 40 f9 ldr x28, [x27, #40]
.section .SUB,"ax",@progbits
nop
@@ -66,33 +66,33 @@ sub:
# CHECK: Disassembly of section .SUB:
# CHECK-NEXT: $x.8:
-# CHECK-NEXT: 2002c: 1f 20 03 d5 nop
+# CHECK-NEXT: 21002c: 1f 20 03 d5 nop
# CHECK: sub:
-# CHECK-NEXT: 20030: 1f 20 03 d5 nop
+# CHECK-NEXT: 210030: 1f 20 03 d5 nop
.section .R_AARCH64_CALL26,"ax",@progbits
call26:
bl sub
-# S = 0x2002c, A = 0x4, P = 0x20034
+# S = 0x21002c, A = 0x4, P = 0x210034
# R = S + A - P = -0x4 = 0xfffffffc
# (R & 0x0ffffffc) >> 2 = 0x03ffffff
# 0x94000000 | 0x03ffffff = 0x97ffffff
# CHECK: Disassembly of section .R_AARCH64_CALL26:
# CHECK-NEXT: call26:
-# CHECK-NEXT: 20034: ff ff ff 97 bl #-4
+# CHECK-NEXT: 210034: ff ff ff 97 bl #-4
.section .R_AARCH64_JUMP26,"ax",@progbits
jump26:
b sub
-# S = 0x2002c, A = 0x4, P = 0x20038
+# S = 0x21002c, A = 0x4, P = 0x210038
# R = S + A - P = -0x8 = 0xfffffff8
# (R & 0x0ffffffc) >> 2 = 0x03fffffe
# 0x14000000 | 0x03fffffe = 0x17fffffe
# CHECK: Disassembly of section .R_AARCH64_JUMP26:
# CHECK-NEXT: jump26:
-# CHECK-NEXT: 20038: fe ff ff 17 b #-8
+# CHECK-NEXT: 210038: fe ff ff 17 b #-8
.section .R_AARCH64_LDST32_ABS_LO12_NC,"ax",@progbits
ldst32:
@@ -101,12 +101,12 @@ foo32:
.asciz "foo"
.size mystr, 3
-# S = 0x2003c, A = 0x4
+# S = 0x21003c, A = 0x4
# R = ((S + A) & 0xFFC) << 8 = 0x00004000
# 0x00004000 | 0xbd4000a4 = 0xbd4040a4
# CHECK: Disassembly of section .R_AARCH64_LDST32_ABS_LO12_NC:
# CHECK-NEXT: ldst32:
-# CHECK-NEXT: 2003c: a4 40 40 bd ldr s4, [x5, #64]
+# CHECK-NEXT: 21003c: a4 40 40 bd ldr s4, [x5, #64]
.section .R_AARCH64_LDST8_ABS_LO12_NC,"ax",@progbits
ldst8:
@@ -115,12 +115,12 @@ foo8:
.asciz "foo"
.size mystr, 3
-# S = 0x20044, A = 0x4
+# S = 0x210044, A = 0x4
# R = ((S + A) & 0xFFF) << 10 = 0x00012000
# 0x00012000 | 0x398001ab = 0x398121ab
# CHECK: Disassembly of section .R_AARCH64_LDST8_ABS_LO12_NC:
# CHECK-NEXT: ldst8:
-# CHECK-NEXT: 20044: ab 21 81 39 ldrsb x11, [x13, #72]
+# CHECK-NEXT: 210044: ab 21 81 39 ldrsb x11, [x13, #72]
.section .R_AARCH64_LDST128_ABS_LO12_NC,"ax",@progbits
ldst128:
@@ -129,14 +129,14 @@ foo128:
.asciz "foo"
.size mystr, 3
-# S = 0x2004c, A = 0x4
+# S = 0x21004c, A = 0x4
# R = ((S + A) & 0xFF8) << 6 = 0x00001400
# 0x00001400 | 0x3dc00274 = 0x3dc01674
# CHECK: Disassembly of section .R_AARCH64_LDST128_ABS_LO12_NC:
# CHECK: ldst128:
-# CHECK: 2004c: 74 16 c0 3d ldr q20, [x19, #80]
+# CHECK: 21004c: 74 16 c0 3d ldr q20, [x19, #80]
#foo128:
-# 20050: 66 6f 6f 00 .word
+# 210050: 66 6f 6f 00 .word
.section .R_AARCH64_LDST16_ABS_LO12_NC,"ax",@progbits
ldst16:
@@ -147,14 +147,14 @@ foo16:
.asciz "foo"
.size mystr, 4
-# S = 0x20054, A = 0x4
+# S = 0x210054, A = 0x4
# R = ((S + A) & 0x0FFC) << 9 = 0xb000
# 0xb000 | 0x7d400271 = 0x7d40b271
# CHECK: Disassembly of section .R_AARCH64_LDST16_ABS_LO12_NC:
# CHECK-NEXT: ldst16:
-# CHECK-NEXT: 20054: 71 c2 40 7d ldr h17, [x19, #96]
-# CHECK-NEXT: 20058: 61 c2 40 79 ldrh w1, [x19, #96]
-# CHECK-NEXT: 2005c: 62 c6 40 79 ldrh w2, [x19, #98]
+# CHECK-NEXT: 210054: 71 c2 40 7d ldr h17, [x19, #96]
+# CHECK-NEXT: 210058: 61 c2 40 79 ldrh w1, [x19, #96]
+# CHECK-NEXT: 21005c: 62 c6 40 79 ldrh w2, [x19, #98]
.section .R_AARCH64_MOVW_UABS,"ax",@progbits
movz1:
diff --git a/test/ELF/aarch64-thunk-pi.s b/test/ELF/aarch64-thunk-pi.s
index d5d956c669b5..345e6ee91f58 100644
--- a/test/ELF/aarch64-thunk-pi.s
+++ b/test/ELF/aarch64-thunk-pi.s
@@ -81,10 +81,14 @@ high_target2:
// 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-EMPTY:
+// CHECK-NEXT: high_target@plt:
// 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-EMPTY:
+// CHECK-NEXT: low_target@plt:
// 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
diff --git a/test/ELF/aarch64-thunk-section-location.s b/test/ELF/aarch64-thunk-section-location.s
index 606c6941579e..36ba33835eda 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
+// RUN: llvm-objdump -d -start-address=136118280 -stop-address=136118292 -triple=aarch64-linux-gnu %t2 | FileCheck %s
// Check that the range extension thunks are dumped close to the aarch64 branch
// range of 128 MiB
.section .text.1, "ax", %progbits
@@ -35,7 +35,7 @@ high_target:
ret
// CHECK: __AArch64AbsLongThunk_high_target:
-// CHECK-NEXT: 7fe0008: 50 00 00 58 ldr x16, #8
-// CHECK-NEXT: 7fe000c: 00 02 1f d6 br x16
+// CHECK-NEXT: 81d0008: 50 00 00 58 ldr x16, #8
+// CHECK-NEXT: 81d000c: 00 02 1f d6 br x16
// CHECK: $d:
-// CHECK-NEXT: 7fe0010: 00 10 02 08 .word 0x08021000
+// CHECK-NEXT: 81d0010: 00 10 21 08 .word 0x08211000
diff --git a/test/ELF/aarch64-tls-gdie.s b/test/ELF/aarch64-tls-gdie.s
index ab7461ac2973..3b795f60e0d8 100644
--- a/test/ELF/aarch64-tls-gdie.s
+++ b/test/ELF/aarch64-tls-gdie.s
@@ -21,14 +21,14 @@ _start:
// SEC-NEXT: SHF_ALLOC
// SEC-NEXT: SHF_WRITE
// SEC-NEXT: ]
-// SEC-NEXT: Address: 0x300B0
+// SEC-NEXT: Address: 0x2200B0
-// page(0x300B0) - page(0x20004) = 65536
+// page(0x2200B0) - page(0x20004) = 65536
// 0x0B0 = 176
// CHECK: _start:
-// CHECK-NEXT: 20000: {{.*}} nop
-// CHECK-NEXT: 20004: {{.*}} adrp x0, #65536
-// CHECK-NEXT: 20008: {{.*}} ldr x0, [x0, #176]
-// CHECK-NEXT: 2000c: {{.*}} nop
-// CHECK-NEXT: 20010: {{.*}} nop
+// CHECK-NEXT: 210000: {{.*}} nop
+// CHECK-NEXT: 210004: {{.*}} adrp x0, #65536
+// CHECK-NEXT: 210008: {{.*}} ldr x0, [x0, #176]
+// CHECK-NEXT: 21000c: {{.*}} nop
+// CHECK-NEXT: 210010: {{.*}} nop
diff --git a/test/ELF/aarch64-tls-gdle.s b/test/ELF/aarch64-tls-gdle.s
index 6763c50838da..882ec8c1ae17 100644
--- a/test/ELF/aarch64-tls-gdle.s
+++ b/test/ELF/aarch64-tls-gdle.s
@@ -5,17 +5,17 @@
# RUN: llvm-objdump -d %tout | FileCheck %s
# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
-#Local-Dynamic to Initial-Exec relax creates no
+#Local-Dynamic to Local-Exec relax creates no
#RELOC: Relocations [
#RELOC-NEXT: ]
-# TCB size = 0x16 and foo is first element from TLS register.
+# TCB size = 64 and foo is first element from TLS register.
# CHECK: Disassembly of section .text:
# CHECK: _start:
-# CHECK: 20000: 00 00 a0 d2 movz x0, #0, lsl #16
-# CHECK: 20004: 00 02 80 f2 movk x0, #16
-# CHECK: 20008: 1f 20 03 d5 nop
-# CHECK: 2000c: 1f 20 03 d5 nop
+# CHECK: 210000: 00 00 a0 d2 movz x0, #0, lsl #16
+# CHECK: 210004: 00 08 80 f2 movk x0, #64
+# CHECK: 210008: 1f 20 03 d5 nop
+# CHECK: 21000c: 1f 20 03 d5 nop
.globl _start
_start:
diff --git a/test/ELF/aarch64-tls-ie.s b/test/ELF/aarch64-tls-ie.s
index fba7cd8af51f..5786fe3a0a97 100644
--- a/test/ELF/aarch64-tls-ie.s
+++ b/test/ELF/aarch64-tls-ie.s
@@ -15,7 +15,7 @@
#RELOC-NEXT: SHF_ALLOC
#RELOC-NEXT: SHF_WRITE
#RELOC-NEXT: ]
-#RELOC-NEXT: Address: 0x300B0
+#RELOC-NEXT: Address: 0x2200B0
#RELOC-NEXT: Offset: 0x200B0
#RELOC-NEXT: Size: 16
#RELOC-NEXT: Link: 0
@@ -25,21 +25,21 @@
#RELOC-NEXT: }
#RELOC: Relocations [
#RELOC-NEXT: Section ({{.*}}) .rela.dyn {
-#RELOC-NEXT: 0x300B8 R_AARCH64_TLS_TPREL64 bar 0x0
-#RELOC-NEXT: 0x300B0 R_AARCH64_TLS_TPREL64 foo 0x0
+#RELOC-NEXT: 0x2200B8 R_AARCH64_TLS_TPREL64 bar 0x0
+#RELOC-NEXT: 0x2200B0 R_AARCH64_TLS_TPREL64 foo 0x0
#RELOC-NEXT: }
#RELOC-NEXT:]
-# Page(0x300B0) - Page(0x20000) = 0x10000 = 65536
-# 0x300B0 & 0xff8 = 0xB0 = 176
-# Page(0x300B8) - Page(0x20000) = 0x10000 = 65536
-# 0x300B8 & 0xff8 = 0xB8 = 184
+# Page(0x2200B0) - Page(0x210000) = 0x10000 = 65536
+# 0x2200B0 & 0xff8 = 0xB0 = 176
+# Page(0x2200B8) - Page(0x210000) = 0x10000 = 65536
+# 0x2200B8 & 0xff8 = 0xB8 = 184
#CHECK: Disassembly of section .text:
#CHECK: _start:
-#CHECK: 20000: 80 00 00 90 adrp x0, #65536
-#CHECK: 20004: 00 58 40 f9 ldr x0, [x0, #176]
-#CHECK: 20008: 80 00 00 90 adrp x0, #65536
-#CHECK: 2000c: 00 5c 40 f9 ldr x0, [x0, #184]
+#CHECK: 210000: 80 00 00 90 adrp x0, #65536
+#CHECK: 210004: 00 58 40 f9 ldr x0, [x0, #176]
+#CHECK: 210008: 80 00 00 90 adrp x0, #65536
+#CHECK: 21000c: 00 5c 40 f9 ldr x0, [x0, #184]
.globl _start
_start:
diff --git a/test/ELF/aarch64-tls-iele.s b/test/ELF/aarch64-tls-iele.s
index c97a578f8dc2..0229d6676cd5 100644
--- a/test/ELF/aarch64-tls-iele.s
+++ b/test/ELF/aarch64-tls-iele.s
@@ -9,13 +9,13 @@
# RELOC: Relocations [
# RELOC-NEXT: ]
-# TCB size = 0x16 and foo is first element from TLS register.
+# TCB size = 64 and foo is first element from TLS register.
# CHECK: Disassembly of section .text:
# CHECK: _start:
-# CHECK-NEXT: 20000: 00 00 a0 d2 movz x0, #0, lsl #16
-# CHECK-NEXT: 20004: 80 02 80 f2 movk x0, #20
-# CHECK-NEXT: 20008: 00 00 a0 d2 movz x0, #0, lsl #16
-# CHECK-NEXT: 2000c: 00 02 80 f2 movk x0, #16
+# CHECK-NEXT: 210000: 00 00 a0 d2 movz x0, #0, lsl #16
+# CHECK-NEXT: 210004: 80 08 80 f2 movk x0, #68
+# CHECK-NEXT: 210008: 00 00 a0 d2 movz x0, #0, lsl #16
+# CHECK-NEXT: 21000c: 00 08 80 f2 movk x0, #64
.section .tdata
.align 2
diff --git a/test/ELF/aarch64-tls-le.s b/test/ELF/aarch64-tls-le.s
index e5b1c208a185..49c322facb12 100644
--- a/test/ELF/aarch64-tls-le.s
+++ b/test/ELF/aarch64-tls-le.s
@@ -4,7 +4,7 @@
# RUN: llvm-objdump -d %tout | FileCheck %s
# RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s
-#Local-Dynamic to Initial-Exec relax creates no
+#Local-Dynamic to Local-Exec relax creates no
#RELOC: Relocations [
#RELOC-NEXT: ]
@@ -13,19 +13,36 @@ _start:
mrs x0, TPIDR_EL0
add x0, x0, :tprel_hi12:v1
add x0, x0, :tprel_lo12_nc:v1
+ mrs x0, TPIDR_EL0
+ add x0, x0, :tprel_hi12:v2
+ add x0, x0, :tprel_lo12_nc:v2
-# TCB size = 0x16 and foo is first element from TLS register.
+# TCB size = 64 and foo is first element from TLS register.
#CHECK: Disassembly of section .text:
#CHECK: _start:
-#CHECK: 20000: 40 d0 3b d5 mrs x0, TPIDR_EL0
-#CHECK: 20004: 00 00 40 91 add x0, x0, #0, lsl #12
-#CHECK: 20008: 00 40 00 91 add x0, x0, #16
+#CHECK: 210000: 40 d0 3b d5 mrs x0, TPIDR_EL0
+#CHECK: 210004: 00 00 40 91 add x0, x0, #0, lsl #12
+#CHECK: 210008: 00 00 01 91 add x0, x0, #64
+#CHECK: 21000c: 40 d0 3b d5 mrs x0, TPIDR_EL0
+#CHECK: 210010: 00 fc 7f 91 add x0, x0, #4095, lsl #12
+#CHECK: 210014: 00 e0 3f 91 add x0, x0, #4088
-.type v1,@object
.section .tbss,"awT",@nobits
+
+.type v1,@object
.globl v1
.p2align 2
v1:
.word 0
.size v1, 4
+# The current offset from the thread pointer is 68. Raise it to just below the
+# 24-bit limit.
+.space (0xfffff8 - 68)
+
+.type v2,@object
+.globl v2
+.p2align 2
+v2:
+.word 0
+.size v2, 4
diff --git a/test/ELF/aarch64-tlsld-ldst.s b/test/ELF/aarch64-tlsld-ldst.s
index 9de3a38044d9..8ebdc2f152a6 100644
--- a/test/ELF/aarch64-tlsld-ldst.s
+++ b/test/ELF/aarch64-tlsld-ldst.s
@@ -25,28 +25,28 @@ _start: mrs x8, TPIDR_EL0
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-NEXT: 210000: 48 d0 3b d5 mrs x8, TPIDR_EL0
+// 0x0 + c40 = 0xc40 = tcb (64-bytes) + var0
+// CHECK-NEXT: 210004: 08 01 40 91 add x8, x8, #0, lsl #12
+// CHECK-NEXT: 210008: 14 11 c3 3d ldr q20, [x8, #3136]
+// 0x1000 + 0x850 = 0x1850 = tcb + var1
+// CHECK-NEXT: 21000c: 08 05 40 91 add x8, x8, #1, lsl #12
+// CHECK-NEXT: 210010: 00 29 44 f9 ldr x0, [x8, #2128]
+// 0x2000 + 0x458 = 0x2458 = tcb + var2
+// CHECK-NEXT: 210014: 08 09 40 91 add x8, x8, #2, lsl #12
+// CHECK-NEXT: 210018: 00 59 44 b9 ldr w0, [x8, #1112]
+// 0x3000 + 0x5c = 0x305c = tcb + var3
+// CHECK-NEXT: 21001c: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 210020: 00 b9 40 79 ldrh w0, [x8, #92]
+// 0x3000 + 0xc5e = 0x3c5e = tcb + var4
+// CHECK-NEXT: 210024: 08 0d 40 91 add x8, x8, #3, lsl #12
+// CHECK-NEXT: 210028: 00 79 71 39 ldrb w0, [x8, #3166]
-// 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
+// CHECK-SYMS: 0000000000000c00 16 TLS GLOBAL DEFAULT 2 var0
+// CHECK-SYMS-NEXT: 0000000000001810 8 TLS GLOBAL DEFAULT 2 var1
+// CHECK-SYMS-NEXT: 0000000000002418 4 TLS GLOBAL DEFAULT 2 var2
+// CHECK-SYMS-NEXT: 000000000000301c 2 TLS GLOBAL DEFAULT 2 var3
+// CHECK-SYMS-NEXT: 0000000000003c1e 1 TLS GLOBAL DEFAULT 2 var4
.globl var0
.globl var1
@@ -59,12 +59,12 @@ _start: mrs x8, TPIDR_EL0
.type var3,@object
.section .tbss,"awT",@nobits
- .balign 16
+ .balign 64
.space 1024 * 3
var0:
.quad 0
.quad 0
- .size var1, 16
+ .size var0, 16
.space 1024 * 3
var1:
.quad 0
@@ -72,14 +72,14 @@ var1:
.space 1024 * 3
var2:
.word 0
- .size var1, 4
+ .size var2, 4
.space 1024 * 3
var3:
.hword 0
- .size var2, 2
+ .size var3, 2
.space 1024 * 3
var4:
.byte 0
- .size var3, 1
+ .size var4, 1
.space 1024 * 3
diff --git a/test/ELF/aarch64-tstbr14-reloc.s b/test/ELF/aarch64-tstbr14-reloc.s
index 779ca6b808a8..9e9d969d9bb6 100644
--- a/test/ELF/aarch64-tstbr14-reloc.s
+++ b/test/ELF/aarch64-tstbr14-reloc.s
@@ -13,19 +13,19 @@
# 0x11028 - 24 = 0x20010
# CHECK: Disassembly of section .text:
# CHECK-NEXT: _foo:
-# CHECK-NEXT: 20000: {{.*}} nop
-# CHECK-NEXT: 20004: {{.*}} nop
-# CHECK-NEXT: 20008: {{.*}} nop
-# CHECK-NEXT: 2000c: {{.*}} nop
+# CHECK-NEXT: 210000: {{.*}} nop
+# CHECK-NEXT: 210004: {{.*}} nop
+# CHECK-NEXT: 210008: {{.*}} nop
+# CHECK-NEXT: 21000c: {{.*}} nop
# CHECK: _bar:
-# CHECK-NEXT: 20010: {{.*}} nop
-# CHECK-NEXT: 20014: {{.*}} nop
-# CHECK-NEXT: 20018: {{.*}} nop
+# CHECK-NEXT: 210010: {{.*}} nop
+# CHECK-NEXT: 210014: {{.*}} nop
+# CHECK-NEXT: 210018: {{.*}} nop
# CHECK: _start:
-# CHECK-NEXT: 2001c: {{.*}} tbnz w3, #15, #-28
-# CHECK-NEXT: 20020: {{.*}} tbnz w3, #15, #-16
-# CHECK-NEXT: 20024: {{.*}} tbz x6, #45, #-36
-# CHECK-NEXT: 20028: {{.*}} tbz x6, #45, #-24
+# CHECK-NEXT: 21001c: {{.*}} tbnz w3, #15, #-28
+# CHECK-NEXT: 210020: {{.*}} tbnz w3, #15, #-16
+# CHECK-NEXT: 210024: {{.*}} tbz x6, #45, #-36
+# CHECK-NEXT: 210028: {{.*}} tbz x6, #45, #-24
#DSOREL: Section {
#DSOREL: Index:
@@ -79,10 +79,14 @@
#DSO-NEXT: 10044: {{.*}} nop
#DSO-NEXT: 10048: {{.*}} nop
#DSO-NEXT: 1004c: {{.*}} nop
+#DSO-EMPTY:
+#DSO-NEXT: _foo@plt:
#DSO-NEXT: 10050: {{.*}} adrp x16, #65536
#DSO-NEXT: 10054: {{.*}} ldr x17, [x16, #24]
#DSO-NEXT: 10058: {{.*}} add x16, x16, #24
#DSO-NEXT: 1005c: {{.*}} br x17
+#DSO-EMPTY:
+#DSO-NEXT: _bar@plt:
#DSO-NEXT: 10060: {{.*}} adrp x16, #65536
#DSO-NEXT: 10064: {{.*}} ldr x17, [x16, #32]
#DSO-NEXT: 10068: {{.*}} add x16, x16, #32
diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s
index e2316acf36a0..ef14bfc237ab 100644
--- a/test/ELF/aarch64-undefined-weak.s
+++ b/test/ELF/aarch64-undefined-weak.s
@@ -34,16 +34,16 @@ _start:
ldr x8, target
// CHECK: Disassembly of section .text:
-// 131072 = 0x20000
-// CHECK: 20000: {{.*}} b #4
-// CHECK-NEXT: 20004: {{.*}} bl #4
-// CHECK-NEXT: 20008: {{.*}} b.eq #4
-// CHECK-NEXT: 2000c: {{.*}} cbz x1, #4
-// CHECK-NEXT: 20010: {{.*}} adr x0, #0
-// CHECK-NEXT: 20014: {{.*}} adrp x0, #-131072
-// CHECK: 20018: {{.*}} .word 0x00000000
-// CHECK-NEXT: 2001c: {{.*}} .word 0x00000000
-// CHECK-NEXT: 20020: {{.*}} .word 0x00000000
-// CHECK-NEXT: 20024: {{.*}} .short 0x0000
+// 2162688 = 0x210000
+// CHECK: 210000: {{.*}} b #4
+// CHECK-NEXT: 210004: {{.*}} bl #4
+// CHECK-NEXT: 210008: {{.*}} b.eq #4
+// CHECK-NEXT: 21000c: {{.*}} cbz x1, #4
+// CHECK-NEXT: 210010: {{.*}} adr x0, #0
+// CHECK-NEXT: 210014: {{.*}} adrp x0, #0
+// CHECK: 210018: {{.*}} .word 0x00000000
+// CHECK-NEXT: 21001c: {{.*}} .word 0x00000000
+// CHECK-NEXT: 210020: {{.*}} .word 0x00000000
+// CHECK-NEXT: 210024: {{.*}} .short 0x0000
// CHECK: $x.2:
-// CHECK-NEXT: 20026: {{.*}} ldr x8, #0
+// CHECK-NEXT: 210026: {{.*}} ldr x8, #0
diff --git a/test/ELF/amdgpu-elf-flags-err.s b/test/ELF/amdgpu-elf-flags-err.s
index b5619352fb04..ae68afa6586d 100644
--- a/test/ELF/amdgpu-elf-flags-err.s
+++ b/test/ELF/amdgpu-elf-flags-err.s
@@ -1,6 +1,6 @@
# 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: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx802 -mattr=-code-object-v3 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=-code-object-v3 -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: {{.*}}-1.o
diff --git a/test/ELF/amdgpu-elf-flags.s b/test/ELF/amdgpu-elf-flags.s
index d062dac748ea..c96913cf31d3 100644
--- a/test/ELF/amdgpu-elf-flags.s
+++ b/test/ELF/amdgpu-elf-flags.s
@@ -1,6 +1,6 @@
# 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: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=-code-object-v3 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -mattr=-code-object-v3 -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
diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s
index 01b1ef2757fb..5888201acf37 100644
--- a/test/ELF/amdgpu-kernels.s
+++ b/test/ELF/amdgpu-kernels.s
@@ -1,5 +1,5 @@
# REQUIRES: amdgpu
-# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri -mattr=-code-object-v3 %s -o %t.o
# RUN: ld.lld -shared %t.o -o %t
# RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s
diff --git a/test/ELF/archive-fetch.s b/test/ELF/archive-fetch.s
new file mode 100644
index 000000000000..201218f4cc26
--- /dev/null
+++ b/test/ELF/archive-fetch.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+
+# We have a code in LLD that prevents fetching the same object from archive file twice.
+# This test triggers that code, without it we would fail to link output.
+
+# RUN: echo '.globl foo, bar; foo:' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tfoo.o
+# RUN: echo '.globl foo, bar; bar:' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tbar.o
+# RUN: rm -f %t.a
+# RUN: llvm-ar rcs %t.a %tfoo.o %tbar.o
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.a %t.o -o /dev/null
+
+_start:
+callq foo
diff --git a/test/ELF/arm-bl-v6-inrange.s b/test/ELF/arm-bl-v6-inrange.s
new file mode 100644
index 000000000000..0e186c53f3c3
--- /dev/null
+++ b/test/ELF/arm-bl-v6-inrange.s
@@ -0,0 +1,47 @@
+// REQUIRES: arm
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv6-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN: .callee1 0x100004 : { *(.callee_low) } \
+// RUN: .caller 0x500000 : { *(.text) } \
+// RUN: .callee2 0x900004 : { *(.callee_high) } } " > %t.script
+// RUN: ld.lld %t --script %t.script -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=thumbv6-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s
+// RUN: llvm-objdump -d -triple=armv6-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s
+
+// On older Arm Architectures such as v5 and v6 the Thumb BL and BLX relocation
+// uses a slightly different encoding that has a lower range. These relocations
+// are at the extreme range of what is permitted.
+ .thumb
+ .text
+ .syntax unified
+ .cpu arm1176jzf-s
+ .globl _start
+ .type _start,%function
+_start:
+ bl thumbfunc
+ bl armfunc
+ bx lr
+
+ .section .callee_low, "ax", %progbits
+ .globl thumbfunc
+ .type thumbfunc, %function
+thumbfunc:
+ bx lr
+// CHECK-THUMB: Disassembly of section .callee1:
+// CHECK-THUMB-NEXT: thumbfunc:
+// CHECK-THUMB-NEXT: 100004: 70 47 bx lr
+// CHECK-THUMB-NEXT: Disassembly of section .caller:
+// CHECK-THUMB-NEXT: _start:
+// CHECK-THUMB-NEXT: 500000: 00 f4 00 f8 bl #-4194304
+// CHECK-THUMB-NEXT: 500004: ff f3 fe ef blx #4194300
+// CHECK-THUMB-NEXT: 500008: 70 47 bx lr
+
+ .arm
+ .section .callee_high, "ax", %progbits
+ .globl armfunc
+ .type armfunc, %function
+armfunc:
+ bx lr
+// CHECK-ARM: Disassembly of section .callee2:
+// CHECK-ARM-NEXT: armfunc:
+// CHECK-ARM-NEXT: 900004: 1e ff 2f e1 bx lr
diff --git a/test/ELF/arm-bl-v6.s b/test/ELF/arm-bl-v6.s
index c27a99e6b9e7..13be7694120d 100644
--- a/test/ELF/arm-bl-v6.s
+++ b/test/ELF/arm-bl-v6.s
@@ -1,22 +1,23 @@
// 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
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv6-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv6-none-linux-gnueabi -start-address=69632 -stop-address=69640 %t2 | FileCheck -check-prefix=CHECK-ARM1 %s
+// RUN: llvm-objdump -d -triple=thumbv6-none-linux-gnueabi %t2 -start-address=69640 -stop-address=69644 | FileCheck -check-prefix=CHECK-THUMB1 %s
+// RUN: llvm-objdump -d -triple=armv6-none-linux-gnueabi -start-address=2166796 -stop-address=2166804 %t2 | FileCheck -check-prefix=CHECK-ARM2 %s
+// RUN: llvm-objdump -d -triple=thumbv6-none-linux-gnueabi %t2 -start-address=6365184 -stop-address=6365186 | FileCheck -check-prefix=CHECK-THUMB2 %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
// BL that is out of range on ARM v6 and requires a range extension thunk.
// As v6 does not support MOVT or MOVW instructions the Thunk must not
-// use these instructions either. At present we don't support v6 so we give a
-// warning for unsupported features.
+// use these instructions either.
+
-// CHECK: warning: lld uses extended branch encoding, no object with architecture supporting feature detected.
-// CHECK-NEXT: warning: lld may use movt/movw, no object with architecture supporting feature detected.
// ARM v6 supports blx so we shouldn't see the blx not supported warning.
// CHECK-NOT: warning: lld uses blx instruction, no object with architecture supporting feature detected.
.text
.syntax unified
.cpu arm1176jzf-s
- .eabi_attribute 6, 6 @ Tag_CPU_arch
.globl _start
.type _start,%function
.balign 0x1000
@@ -24,6 +25,10 @@ _start:
bl thumbfunc
bx lr
+// CHECK-ARM1: Disassembly of section .text:
+// CHECK-ARM1-NEXT: _start:
+// CHECK-ARM1-NEXT: 11000: 00 00 00 fa blx #0 <thumbfunc>
+// CHECK-ARM1-NEXT: 11004: 1e ff 2f e1 bx lr
.thumb
.section .text.2, "ax", %progbits
.globl thumbfunc
@@ -31,11 +36,17 @@ _start:
thumbfunc:
bl farthumbfunc
-// 6 Megabytes, enough to make farthumbfunc out of range of caller on a v6
-// Arm, but not on a v7 Arm.
+// CHECK-THUMB1: thumbfunc:
+// CHECK-THUMB1-NEXT: 11008: 00 f2 00 e8 blx #2097152
+// 6 Megabytes, enough to make farthumbfunc out of range of caller
+// on a v6 Arm, but not on a v7 Arm.
+
.section .text.3, "ax", %progbits
.space 0x200000
-
+// CHECK-ARM2: __ARMv5ABSLongThunk_farthumbfunc:
+// CHECK-ARM2-NEXT: 21100c: 04 f0 1f e5 ldr pc, [pc, #-4]
+// CHECK-ARM2: $d:
+// CHECK-ARM2-NEXT: 211010: 01 20 61 00 .word 0x00612001
.section .text.4, "ax", %progbits
.space 0x200000
@@ -49,3 +60,5 @@ thumbfunc:
.type farthumbfunc,%function
farthumbfunc:
bx lr
+// CHECK-THUMB2: farthumbfunc:
+// CHECK-THUMB2-NEXT: 612000: 70 47 bx lr
diff --git a/test/ELF/arm-blx-v4t.s b/test/ELF/arm-blx-v4t.s
index f526b3b01f4a..6c2b69885a10 100644
--- a/test/ELF/arm-blx-v4t.s
+++ b/test/ELF/arm-blx-v4t.s
@@ -1,19 +1,16 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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
// features.
-// CHECK: warning: lld uses blx instruction, no object with architecture supporting feature detected.
-// CHECK-NEXT: warning: lld uses extended branch encoding, no object with architecture supporting feature detected.
-// CHECK-NEXT: warning: lld may use movt/movw, no object with architecture supporting feature detected.
+// CHECK: warning: lld uses blx instruction, no object with architecture supporting feature detected
.text
.syntax unified
.cpu arm7tdmi
- .eabi_attribute 6, 2 @ Tag_CPU_arch
.arm
.globl _start
.type _start,%function
diff --git a/test/ELF/arm-branch-rangethunk.s b/test/ELF/arm-branch-rangethunk.s
index 739a7707dbec..7d83c8735cb0 100644
--- a/test/ELF/arm-branch-rangethunk.s
+++ b/test/ELF/arm-branch-rangethunk.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/far-arm-abs.s -o %tfar
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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 --check-prefix=SHORT %s
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-long-arm-abs.s -o %tfarlong
+// RUN: llvm-mc -arm-add-build-attributes -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
diff --git a/test/ELF/arm-branch-undef-weak-plt-thunk.s b/test/ELF/arm-branch-undef-weak-plt-thunk.s
index f47ed61ca5a6..919d4f5bdc33 100644
--- a/test/ELF/arm-branch-undef-weak-plt-thunk.s
+++ b/test/ELF/arm-branch-undef-weak-plt-thunk.s
@@ -1,7 +1,7 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-shared.s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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: llvm-mc -arm-add-build-attributes -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
diff --git a/test/ELF/arm-combined-dynrel-ifunc.s b/test/ELF/arm-combined-dynrel-ifunc.s
new file mode 100644
index 000000000000..2761357fd98d
--- /dev/null
+++ b/test/ELF/arm-combined-dynrel-ifunc.s
@@ -0,0 +1,49 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-linux-gnueabihf %p/Inputs/arm-shared.s -o %t-lib.o
+// RUN: llvm-mc -filetype=obj -arm-add-build-attributes -triple=armv7a-linux-gnueabihf %s -o %t.o
+// RUN: ld.lld %t-lib.o --shared -o %t.so
+// RUN: echo "SECTIONS { \
+// RUN: .text : { *(.text) } \
+// RUN: .rela.dyn : { *(.rel.dyn) *(.rel.plt) } \
+// RUN: } " > %t.script
+// RUN: ld.lld %t.o -o %t.axf %t.so --script %t.script
+// RUN: llvm-readobj --section-headers --dynamic-table %t.axf | FileCheck %s
+
+// The linker script above combines the .rela.dyn and .rela.plt into a single
+// table. ELF is clear that the DT_PLTRELSZ should match the subset of
+// relocations that is associated with the PLT. It is less clear about what
+// the value of DT_RELASZ should be. ELF implies that it should be the size
+// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
+// glibc permits this as long as .rela.plt comes after .rela.dyn in the
+// combined table. In the ARM case irelative relocations do not count as PLT
+// relocs.
+
+.text
+.globl indirect
+.type indirect,%gnu_indirect_function
+indirect:
+ bx lr
+
+.globl bar2 // from Inputs/arm-shared.s
+
+.text
+.globl _start
+.type _start,%function
+main:
+ bl indirect
+ bl bar2
+ .word indirect(got)
+ .word bar2(got)
+ bx lr
+
+// CHECK: Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_REL
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 24
+
+// CHECK: 0x00000012 RELSZ 24 (bytes)
+// CHECK: 0x00000002 PLTRELSZ 8 (bytes)
diff --git a/test/ELF/arm-extreme-range-pi-thunk.s b/test/ELF/arm-extreme-range-pi-thunk.s
new file mode 100644
index 000000000000..5daf38807ba1
--- /dev/null
+++ b/test/ELF/arm-extreme-range-pi-thunk.s
@@ -0,0 +1,82 @@
+// REQUIRES: arm
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS {" > %t.script
+// RUN: echo " .text_low 0x130 : { *(.text) }" >> %t.script
+// RUN: echo " .text_high 0xf0000000 : AT(0x1000) { *(.text_high) }" >> %t.script
+// RUN: echo " } " >> %t.script
+// RUN: ld.lld --script %t.script --pie --static %t -o %t2 2>&1
+// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s
+
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t3
+// RUN: ld.lld --script %t.script --pie %t3 -o %t4 2>&1
+// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-THUMB %s
+
+// Check that we can create Arm and Thumb v7a Position Independent Thunks that
+// can span the address space without triggering overflow errors. We use an
+// AT(0x1000) for .text_high to avoid creating an almost 4Gb size file.
+ .syntax unified
+ .text
+ .global _start
+ .type _start, %function
+_start:
+ bl high
+ bx lr
+
+ .section .text_high, "ax", %progbits
+ .global high
+ .type high, %function
+high:
+ bl _start
+ bx lr
+
+// ARMv7a instructions and relocations.
+
+// CHECK: Disassembly of section .text_low:
+// CHECK-NEXT: _start:
+// CHECK-NEXT: 130: 00 00 00 eb bl #0 <__ARMV7PILongThunk_high>
+// CHECK-NEXT: 134: 1e ff 2f e1 bx lr
+
+// CHECK: __ARMV7PILongThunk_high:
+// CHECK-NEXT: 138: b8 ce 0f e3 movw r12, #65208
+// CHECK-NEXT: 13c: ff cf 4e e3 movt r12, #61439
+// 0x140 + 0xEFFF0000 + 0x0000FEB8 + 8 = 0xf0000000 = high
+// CHECK-NEXT: 140: 0f c0 8c e0 add r12, r12, pc
+// CHECK-NEXT: 144: 1c ff 2f e1 bx r12
+
+// CHECK: Disassembly of section .text_high:
+// CHECK-NEXT: high:
+// CHECK-NEXT: f0000000: 00 00 00 eb bl #0 <__ARMV7PILongThunk__start>
+// CHECK-NEXT: f0000004: 1e ff 2f e1 bx lr
+
+// CHECK: __ARMV7PILongThunk__start:
+// CHECK-NEXT: f0000008: 18 c1 00 e3 movw r12, #280
+// CHECK-NEXT: f000000c: 00 c0 41 e3 movt r12, #4096
+// 0xf0000010 + 0x10000000 + 0x0000118 + 8 = bits32(0x100000130),0x130 = _start
+// CHECK-NEXT: f0000010: 0f c0 8c e0 add r12, r12, pc
+// CHECK-NEXT: f0000014: 1c ff 2f e1 bx r12
+
+// Thumbv7a instructions and relocations
+// CHECK-THUMB: Disassembly of section .text_low:
+// CHECK-THUMB-NEXT: _start:
+// CHECK-THUMB-NEXT: 130: 00 f0 02 f8 bl #4
+// CHECK-THUMB-NEXT: 134: 70 47 bx lr
+// CHECK-THUMB-NEXT: 136: d4 d4 bmi #-88
+
+// CHECK-THUMB: __ThumbV7PILongThunk_high:
+// CHECK-THUMB-NEXT: 138: 4f f6 bd 6c movw r12, #65213
+// CHECK-THUMB-NEXT: 13c: ce f6 ff 7c movt r12, #61439
+// 0x140 + 0xEFFF0000 + 0x0000FEBD + 4 = 0xf0000001 = high
+// CHECK-THUMB-NEXT: 140: fc 44 add r12, pc
+// CHECK-THUMB-NEXT: 142: 60 47 bx r12
+
+// CHECK-THUMB: Disassembly of section .text_high:
+// CHECK-THUMB-NEXT: high:
+// CHECK-THUMB-NEXT: f0000000: 00 f0 02 f8 bl #4
+// CHECK-THUMB-NEXT: f0000004: 70 47 bx lr
+
+// CHECK-THUMB: __ThumbV7PILongThunk__start:
+// CHECK-THUMB-NEXT: f0000008: 40 f2 1d 1c movw r12, #285
+// CHECK-THUMB-NEXT: f000000c: c1 f2 00 0c movt r12, #4096
+// 0xf0000010 + 0x10000000 + 0x000011d +4 = bits32(0x100000131),0x131 = _start
+// CHECK-THUMB-NEXT: f0000010: fc 44 add r12, pc
+// CHECK-THUMB-NEXT: f0000012: 60 47 bx r12
diff --git a/test/ELF/arm-long-thunk-converge.s b/test/ELF/arm-long-thunk-converge.s
index dadc7e5fc9a9..f241a585676d 100644
--- a/test/ELF/arm-long-thunk-converge.s
+++ b/test/ELF/arm-long-thunk-converge.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -triple armv7-unknown-gnu -filetype=obj -o %t %s
+// RUN: llvm-mc -triple armv7-unknown-gnu -arm-add-build-attributes -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
diff --git a/test/ELF/arm-thumb-branch-rangethunk.s b/test/ELF/arm-thumb-branch-rangethunk.s
index 4bbd69214e93..31a239dcdd88 100644
--- a/test/ELF/arm-thumb-branch-rangethunk.s
+++ b/test/ELF/arm-thumb-branch-rangethunk.s
@@ -1,6 +1,6 @@
// 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: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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
.syntax unified
diff --git a/test/ELF/arm-thumb-branch.s b/test/ELF/arm-thumb-branch.s
index 89c081a69b88..043db4b08f97 100644
--- a/test/ELF/arm-thumb-branch.s
+++ b/test/ELF/arm-thumb-branch.s
@@ -1,6 +1,6 @@
// 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: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar
// RUN: echo "SECTIONS { \
// RUN: . = 0xb4; \
// RUN: .callee1 : { *(.callee_low) } \
diff --git a/test/ELF/arm-thumb-condbranch-thunk.s b/test/ELF/arm-thumb-condbranch-thunk.s
index c9365efb73a7..8a5e9c85f510 100644
--- a/test/ELF/arm-thumb-condbranch-thunk.s
+++ b/test/ELF/arm-thumb-condbranch-thunk.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// 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
diff --git a/test/ELF/arm-thumb-interwork-shared.s b/test/ELF/arm-thumb-interwork-shared.s
index 030ac29854b2..5c847367e09b 100644
--- a/test/ELF/arm-thumb-interwork-shared.s
+++ b/test/ELF/arm-thumb-interwork-shared.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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
diff --git a/test/ELF/arm-thumb-interwork-thunk-range.s b/test/ELF/arm-thumb-interwork-thunk-range.s
index d59ee1159920..3c013183791b 100644
--- a/test/ELF/arm-thumb-interwork-thunk-range.s
+++ b/test/ELF/arm-thumb-interwork-thunk-range.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
// 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
diff --git a/test/ELF/arm-thumb-interwork-thunk-v5.s b/test/ELF/arm-thumb-interwork-thunk-v5.s
new file mode 100644
index 000000000000..90aa76e4a3e3
--- /dev/null
+++ b/test/ELF/arm-thumb-interwork-thunk-v5.s
@@ -0,0 +1,66 @@
+// REQUIRES: arm
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv5-none-linux-gnueabi %s -o %t
+// RUN: ld.lld %t -o %t2
+// RUN: llvm-objdump -d %t2 -triple=armv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-ARM %s
+// RUN: llvm-objdump -d %t2 -triple=thumbv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-THUMB %s
+// RUN: ld.lld %t -o %t3 --shared
+// RUN: llvm-objdump -d %t3 -triple=armv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-ARM-PI %s
+// RUN: llvm-objdump -d %t3 -triple=thumbv5-none-linux-gnueabi | FileCheck -check-prefix=CHECK-THUMB-PI %s
+
+// Test ARM Thumb Interworking on older Arm architectures using Thunks that do
+// not use MOVT/MOVW instructions.
+// For pure interworking (not considering range extension) there is only the
+// case of an Arm B to a Thumb Symbol to consider as in older Arm architectures
+// there is no Thumb B.w that we can intercept with a Thunk and we still assume
+// support for the blx instruction for Thumb BL and BLX to an Arm symbol.
+ .arm
+ .text
+ .syntax unified
+ .cpu arm10tdmi
+
+ .text
+ .globl _start
+ .type _start, %function
+ .balign 0x1000
+_start:
+ b thumb_func
+ bl thumb_func
+ blx thumb_func
+ bx lr
+
+// CHECK-ARM: _start:
+// CHECK-ARM-NEXT: 11000: 03 00 00 ea b #12 <__ARMv5ABSLongThunk_thumb_func>
+// CHECK-ARM-NEXT: 11004: 01 00 00 fa blx #4 <thumb_func>
+// CHECK-ARM-NEXT: 11008: 00 00 00 fa blx #0 <thumb_func>
+// CHECK-ARM-NEXT: 1100c: 1e ff 2f e1 bx lr
+
+// CHECK-THUMB: thumb_func:
+// CHECK-THUMB-NEXT: 11010: 70 47 bx lr
+
+// CHECK-ARM: __ARMv5ABSLongThunk_thumb_func:
+// CHECK-ARM-NEXT: 11014: 04 f0 1f e5 ldr pc, [pc, #-4]
+// CHECK-ARM: $d:
+// CHECK-ARM-NEXT: 11018: 11 10 01 00 .word 0x00011011
+
+// CHECK-ARM-PI: _start:
+// CHECK-ARM-PI-NEXT: 1000: 03 00 00 ea b #12 <__ARMV5PILongThunk_thumb_func>
+// CHECK-ARM-PI-NEXT: 1004: 01 00 00 fa blx #4 <thumb_func>
+// CHECK-ARM-PI-NEXT: 1008: 00 00 00 fa blx #0 <thumb_func>
+// CHECK-ARM-PI-NEXT: 100c: 1e ff 2f e1 bx lr
+
+// CHECK-THUMB-PI: thumb_func:
+// CHECK-THUMB-PI-NEXT: 1010: 70 47 bx lr
+
+// CHECK-ARM-PI: __ARMV5PILongThunk_thumb_func:
+// CHECK-ARM-PI-NEXT: 1014: 04 c0 9f e5 ldr r12, [pc, #4]
+// CHECK-ARM-PI-NEXT: 1018: 0c c0 8f e0 add r12, pc, r12
+// CHECK-ARM-PI-NEXT: 101c: 1c ff 2f e1 bx r12
+// CHECK-ARM-PI: $d:
+// CHECK-ARM-PI-NEXT: 1020: f1 ff ff ff .word 0xfffffff1
+
+ .section .text.1, "ax", %progbits
+ .thumb
+ .hidden thumb_func
+ .type thumb_func, %function
+thumb_func:
+ bx lr
diff --git a/test/ELF/arm-thumb-interwork-thunk.s b/test/ELF/arm-thumb-interwork-thunk.s
index df5d6c6b7401..4ff08e0112b7 100644
--- a/test/ELF/arm-thumb-interwork-thunk.s
+++ b/test/ELF/arm-thumb-interwork-thunk.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
// RUN: .R_ARM_JUMP24_callee_1 : { *(.R_ARM_JUMP24_callee_low) } \
diff --git a/test/ELF/arm-thumb-mix-range-thunk-os.s b/test/ELF/arm-thumb-mix-range-thunk-os.s
index b5db2565f2c9..7be56648e965 100644
--- a/test/ELF/arm-thumb-mix-range-thunk-os.s
+++ b/test/ELF/arm-thumb-mix-range-thunk-os.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// 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
diff --git a/test/ELF/arm-thumb-plt-range-thunk-os.s b/test/ELF/arm-thumb-plt-range-thunk-os.s
index 080160bb2474..08907510be88 100644
--- a/test/ELF/arm-thumb-plt-range-thunk-os.s
+++ b/test/ELF/arm-thumb-plt-range-thunk-os.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// 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
diff --git a/test/ELF/arm-thumb-range-thunk-os.s b/test/ELF/arm-thumb-range-thunk-os.s
index 182b18d79cae..281e79a4eb1c 100644
--- a/test/ELF/arm-thumb-range-thunk-os.s
+++ b/test/ELF/arm-thumb-range-thunk-os.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// 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
diff --git a/test/ELF/arm-thumb-thunk-empty-pass.s b/test/ELF/arm-thumb-thunk-empty-pass.s
index ab9da1b8a2c2..6e81b508492f 100644
--- a/test/ELF/arm-thumb-thunk-empty-pass.s
+++ b/test/ELF/arm-thumb-thunk-empty-pass.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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=16846856 -stop-address=16846874 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s
diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s
index 457d460997aa..ad6e79db3625 100644
--- a/test/ELF/arm-thumb-thunk-symbols.s
+++ b/test/ELF/arm-thumb-thunk-symbols.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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
diff --git a/test/ELF/arm-thumb-thunk-v6m.s b/test/ELF/arm-thumb-thunk-v6m.s
new file mode 100644
index 000000000000..bf5afd5edfee
--- /dev/null
+++ b/test/ELF/arm-thumb-thunk-v6m.s
@@ -0,0 +1,61 @@
+// REQUIRES: arm
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv6m-none-eabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN: . = SIZEOF_HEADERS; \
+// RUN: .text_low : { *(.text_low) *(.text_low2) } \
+// RUN: .text_high 0x2000000 : { *(.text_high) *(.text_high2) } \
+// RUN: } " > %t.script
+// RUN: ld.lld --script %t.script %t -o %t2
+// RUN: llvm-objdump -d %t2 -triple=armv6m-none-eabi | FileCheck %s
+// RUN: ld.lld --script %t.script %t -o %t3 --pie
+// RUN: llvm-objdump -d %t3 -triple=armv6m-none-eabi | FileCheck -check-prefix=CHECK-PI %s
+
+// Range extension thunks for Arm Architecture v6m. Only Thumb instructions
+// are permitted which limits the access to instructions that can access the
+// high registers (r8 - r15), this means that the thunks have to spill
+// low registers (r0 - r7) in order to perform the transfer of control.
+
+ .syntax unified
+ .section .text_low, "ax", %progbits
+ .thumb
+ .type _start, %function
+ .balign 4
+ .globl _start
+_start:
+ bl far
+
+ .section .text_high, "ax", %progbits
+ .globl far
+ .type far, %function
+far:
+ bx lr
+
+// CHECK: Disassembly of section .text_low:
+// CHECK-NEXT: _start:
+// CHECK-NEXT: 94: 00 f0 00 f8 bl #0
+// CHECK: __Thumbv6MABSLongThunk_far:
+// CHECK-NEXT: 98: 03 b4 push {r0, r1}
+// CHECK-NEXT: 9a: 01 48 ldr r0, [pc, #4]
+// CHECK-NEXT: 9c: 01 90 str r0, [sp, #4]
+// CHECK-NEXT: 9e: 01 bd pop {r0, pc}
+// CHECK: a0: 01 00 00 02 .word 0x02000001
+// CHECK: Disassembly of section .text_high:
+// CHECK-NEXT: far:
+// CHECK-NEXT: 2000000: 70 47 bx lr
+
+// CHECK-PI: Disassembly of section .text_low:
+// CHECK-PI-NEXT: _start:
+// CHECK-PI-NEXT: 130: 00 f0 00 f8 bl #0
+// CHECK-PI: __Thumbv6MPILongThunk_far:
+// CHECK-PI-NEXT: 134: 01 b4 push {r0}
+// CHECK-PI-NEXT: 136: 02 48 ldr r0, [pc, #8]
+// CHECK-PI-NEXT: 138: 84 46 mov r12, r0
+// CHECK-PI-NEXT: 13a: 01 bc pop {r0}
+// pc = pc (0x13c + 4) + r12 (1fffec1) = 0x2000001 = .far
+// CHECK-PI-NEXT: 13c: e7 44 add pc, r12
+// CHECK-PI-NEXT: 13e: c0 46 mov r8, r8
+// CHECK-PI: 140: c1 fe ff 01 .word 0x01fffec1
+
+// CHECK-PI: Disassembly of section .text_high:
+// CHECK-PI-NEXT: far:
+// CHECK-PI-NEXT: 2000000: 70 47 bx lr
diff --git a/test/ELF/arm-thumb-undefined-weak-narrow.test b/test/ELF/arm-thumb-undefined-weak-narrow.test
new file mode 100644
index 000000000000..15f428e019b0
--- /dev/null
+++ b/test/ELF/arm-thumb-undefined-weak-narrow.test
@@ -0,0 +1,50 @@
+# REQUIRES: arm
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -triple=thumbv7a-linux-gnueabi -d %t | FileCheck %s
+
+# CHECK: Disassembly of section .text:
+# CHECK-NEXT:_start:
+# CHECK-NEXT: 11000: ff e7 b #-2
+
+# Test the R_ARM_THM_JUMP11 relocation (102) to an undefined weak reference
+# It should resolve to the next instruction, which is an offset of -2 which
+# when added to the Thumb PC-bias of 4 is +2. We can't use llvm-mc to construct
+# the object as it relaxes b.n to b.w (R_ARM_JUMP24).
+
+!ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .text
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Content: "fee7"
+ - Type: SHT_REL
+ Name: .rel.text
+ Link: .symtab
+ Info: .text
+ Relocations:
+ - Offset: 0
+ Symbol: undefined_weak
+ Type: R_ARM_THM_JUMP11
+
+Symbols:
+ Global:
+ - Type: STT_FUNC
+ Name: _start
+ Value: 1
+ Section: .text
+ Local:
+ - Type: STT_NOTYPE
+ Name: "$t"
+ Section: .text
+ Value: 0
+ Weak:
+ - Type: STT_NOTYPE
+ Name: undefined_weak
+ Value: 0
+
diff --git a/test/ELF/arm-thunk-edgecase.s b/test/ELF/arm-thunk-edgecase.s
index 81837c7b3284..356687668399 100644
--- a/test/ELF/arm-thunk-edgecase.s
+++ b/test/ELF/arm-thunk-edgecase.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
// RUN: echo "SECTIONS { \
// RUN: .text_armfunc 0x1000 : { *(.text_armfunc) } \
// RUN: .text_thumbfunc 0x11010 : { *(.text_thumbfunc) } \
diff --git a/test/ELF/arm-thunk-largesection.s b/test/ELF/arm-thunk-largesection.s
index d68cd0c76141..940888f185d4 100644
--- a/test/ELF/arm-thunk-largesection.s
+++ b/test/ELF/arm-thunk-largesection.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -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
@@ -16,9 +16,12 @@ _start:
bx lr
.space 0x1000
// CHECK1: Disassembly of section .text:
-// CHECK1-NEXT: _start:
-// CHECK1-NEXT: 11000: 70 47 bx lr
-// CHECK1-NEXT: 11002: 00 00 movs r0, r0
+// CHECK1-NEXT:_start:
+// CHECK1-NEXT: 11000: 70 47 bx lr
+// CHECK1-EMPTY:
+// CHECK-NEXT:$d.1:
+// CHECK-NEXT: 11002: 00 00 .short 0x0000
+
// CHECK2: __Thumbv7ABSLongThunk__start:
// CHECK2-NEXT: 12004: fe f7 fc bf b.w #-4104 <_start>
diff --git a/test/ELF/arm-thunk-linkerscript-dotexpr.s b/test/ELF/arm-thunk-linkerscript-dotexpr.s
index ea741708bc90..4b68ad813bff 100644
--- a/test/ELF/arm-thunk-linkerscript-dotexpr.s
+++ b/test/ELF/arm-thunk-linkerscript-dotexpr.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
// RUN: .text_low : { *(.text_low) *(.text_low2) . = . + 0x2000000 ; *(.text_high) *(.text_high2) } \
diff --git a/test/ELF/arm-thunk-linkerscript-large.s b/test/ELF/arm-thunk-linkerscript-large.s
index 839d7716c278..1b9ec0bc86ff 100644
--- a/test/ELF/arm-thunk-linkerscript-large.s
+++ b/test/ELF/arm-thunk-linkerscript-large.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: .text 0x100000 : { *(.text) } \
// RUN: .textl : { *(.text_l0*) *(.text_l1*) *(.text_l2*) *(.text_l3*) } \
@@ -21,7 +21,8 @@
// per OutputSection basis
.syntax unified
-// Define a function that we can match with .text_l* aligned on a megabyte // boundary
+// Define a function that we can match with .text_l* aligned on a megabyte
+// boundary
.macro FUNCTIONL suff
.section .text_l\suff\(), "ax", %progbits
.thumb
diff --git a/test/ELF/arm-thunk-linkerscript-orphan.s b/test/ELF/arm-thunk-linkerscript-orphan.s
index f05cc0de9069..556e67be3165 100644
--- a/test/ELF/arm-thunk-linkerscript-orphan.s
+++ b/test/ELF/arm-thunk-linkerscript-orphan.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: .text_low 0x100000 : { *(.text_low) } \
// RUN: .text_high 0x2000000 : { *(.text_high) } \
diff --git a/test/ELF/arm-thunk-linkerscript-sort.s b/test/ELF/arm-thunk-linkerscript-sort.s
index 62ea41363f41..8e2a117b5bb6 100644
--- a/test/ELF/arm-thunk-linkerscript-sort.s
+++ b/test/ELF/arm-thunk-linkerscript-sort.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: .text 0x100000 : { *(SORT_BY_NAME(.text.*)) } \
// RUN: }" > %t.script
diff --git a/test/ELF/arm-thunk-linkerscript.s b/test/ELF/arm-thunk-linkerscript.s
index 7728ddf76a97..6e476a21b43f 100644
--- a/test/ELF/arm-thunk-linkerscript.s
+++ b/test/ELF/arm-thunk-linkerscript.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: echo "SECTIONS { \
// RUN: . = SIZEOF_HEADERS; \
// RUN: .text_low : { *(.text_low) *(.text_low2) } \
diff --git a/test/ELF/arm-thunk-multipass.s b/test/ELF/arm-thunk-multipass.s
index b353bb148ff6..33578b1da51d 100644
--- a/test/ELF/arm-thunk-multipass.s
+++ b/test/ELF/arm-thunk-multipass.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t -o %t2 2>&1
// 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
diff --git a/test/ELF/arm-thunk-nosuitable.s b/test/ELF/arm-thunk-nosuitable.s
index cde790665c42..0e08f3f941d2 100644
--- a/test/ELF/arm-thunk-nosuitable.s
+++ b/test/ELF/arm-thunk-nosuitable.s
@@ -1,4 +1,4 @@
-// REQUIRES: ARM
+// 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
@@ -23,8 +23,7 @@ _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
+// CHECK: 211008: 70 47 bx lr
.section .text.2, "ax", %progbits
.space 12 * 1024 * 1024
diff --git a/test/ELF/arm-thunk-re-add.s b/test/ELF/arm-thunk-re-add.s
index 760e18f57313..9e8feb381829 100644
--- a/test/ELF/arm-thunk-re-add.s
+++ b/test/ELF/arm-thunk-re-add.s
@@ -1,5 +1,5 @@
// REQUIRES: arm
-// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
+// RUN: llvm-mc -arm-add-build-attributes -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t
// RUN: ld.lld %t --shared -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
diff --git a/test/ELF/arm-thunk-section-too-large.s b/test/ELF/arm-thunk-section-too-large.s
index 9174093380f7..62b59de51a0d 100644
--- a/test/ELF/arm-thunk-section-too-large.s
+++ b/test/ELF/arm-thunk-section-too-large.s
@@ -1,4 +1,4 @@
-// REQUIRES: ARM
+// 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
diff --git a/test/ELF/arm-tls-le32.s b/test/ELF/arm-tls-le32.s
index 7834dedf1be0..f9a5fa9b2fc9 100644
--- a/test/ELF/arm-tls-le32.s
+++ b/test/ELF/arm-tls-le32.s
@@ -69,9 +69,9 @@ x:
// CHECK: Disassembly of section .text:
// CHECK-NEXT: _start:
-// offset of x from Thread pointer = (TcbSize + 0x0 = 0x8)
-// CHECK-NEXT: 11000: 08 00 00 00
-// offset of z from Thread pointer = (TcbSize + 0x8 = 0x10)
-// CHECK-NEXT: 11004: 10 00 00 00
-// offset of y from Thread pointer = (TcbSize + 0x4 = 0xc)
-// CHECK-NEXT: 11008: 0c 00 00 00
+// offset of x from Thread pointer = (TcbSize + 0x0 = 0x20)
+// CHECK-NEXT: 11000: 20 00 00 00
+// offset of z from Thread pointer = (TcbSize + 0x8 = 0x28)
+// CHECK-NEXT: 11004: 28 00 00 00
+// offset of y from Thread pointer = (TcbSize + 0x4 = 0x24)
+// CHECK-NEXT: 11008: 24 00 00 00
diff --git a/test/ELF/arm-tls-norelax-ie-le.s b/test/ELF/arm-tls-norelax-ie-le.s
index be8af9760481..11c3e4f5dc1a 100644
--- a/test/ELF/arm-tls-norelax-ie-le.s
+++ b/test/ELF/arm-tls-norelax-ie-le.s
@@ -37,5 +37,5 @@ x2:
.type x2, %object
// CHECK: Contents of section .got:
-// x1 at offset 8 from TP, x2 at offset c from TP. Offsets include TCB size of 8
-// CHECK-NEXT: 13064 08000000 0c000000
+// x1 at offset 0x20 from TP, x2 at offset 0x24 from TP. Offsets include TCB size of 0x20
+// CHECK-NEXT: 13064 20000000 24000000
diff --git a/test/ELF/arm-v4bx.test b/test/ELF/arm-v4bx.test
new file mode 100644
index 000000000000..1b39a431417b
--- /dev/null
+++ b/test/ELF/arm-v4bx.test
@@ -0,0 +1,40 @@
+# REQUIRES: arm
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -sections %t | FileCheck %s
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-readelf -sections %t | FileCheck %s
+
+# CHECK: .text
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_ARM
+ Flags: [ EF_ARM_EABI_VER5 ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000004
+ Content: 1EFF2F01
+ - Name: .rel.text
+ Type: SHT_REL
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: ''
+ Type: R_ARM_V4BX
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+DynamicSymbols:
diff --git a/test/ELF/arm-v5-reloc-error.s b/test/ELF/arm-v5-reloc-error.s
new file mode 100644
index 000000000000..90ea36d3df12
--- /dev/null
+++ b/test/ELF/arm-v5-reloc-error.s
@@ -0,0 +1,31 @@
+// REQUIRES: arm
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t
+// RUN: echo "SECTIONS { \
+// RUN: . = SIZEOF_HEADERS; \
+// RUN: .text_low : { *(.text_low) *(.text_low2) } \
+// RUN: .text_high 0x2000000 : { *(.text_high) *(.text_high2) } \
+// RUN: } " > %t.script
+// RUN: not ld.lld --script %t.script %t -o %t2 2>&1 | FileCheck %s
+
+// CHECK: error: relocation R_ARM_THM_JUMP24 to far not supported for Armv5 or Armv6 targets
+
+// Lie about our build attributes. Our triple is armv7a-linux-gnueabi but
+// we are claiming to be Armv5. This can also happen with llvm-mc when we
+// don't have any .eabi_attribute directives in the file or the
+// --arm-add-build-attributes command line isn't used to add them from the
+// triple.
+ .eabi_attribute 6, 5 // Tag_cpu_arch 5 = v5TEJ
+ .thumb
+ .syntax unified
+ .section .text_low, "ax", %progbits
+ .thumb
+ .globl _start
+ .type _start, %function
+_start:
+ b.w far // Will produce relocation not supported in Armv5.
+
+ .section .text_high, "ax", %progbits
+ .globl far
+ .type far, %function
+far:
+ bx lr
diff --git a/test/ELF/as-needed-in-regular.s b/test/ELF/as-needed-in-regular.s
new file mode 100644
index 000000000000..2ba646f85300
--- /dev/null
+++ b/test/ELF/as-needed-in-regular.s
@@ -0,0 +1,24 @@
+# REQUIRES: x86
+
+# RUN: echo '.globl a; .type a, @function; .type a, @function; a: ret' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %ta.o
+# RUN: ld.lld %ta.o --shared --soname=a.so -o %ta.so
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o --as-needed %ta.so -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+# RUN: ld.lld %t.o --as-needed %ta.so --gc-sections -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+
+# The order of %ta.so and %t.o does not matter.
+
+# RUN: ld.lld --as-needed %ta.so %t.o -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+# RUN: ld.lld --as-needed %ta.so %t.o --gc-sections -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+
+# CHECK: a.so
+
+.global _start
+_start:
+ jmp a@PLT
diff --git a/test/ELF/as-needed-not-in-regular.s b/test/ELF/as-needed-not-in-regular.s
new file mode 100644
index 000000000000..cd7efa6d2688
--- /dev/null
+++ b/test/ELF/as-needed-not-in-regular.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+
+# RUN: echo '.globl a1, a2; .type a1, @function; .type a2, @function; a1: a2: ret' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %ta.o
+# RUN: ld.lld %ta.o --shared --soname=a.so -o %ta.so
+
+# RUN: echo '.globl b; .type b, @function; b: jmp a1@PLT' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tb.o
+# RUN: ld.lld %tb.o %ta.so --shared --soname=b.so -o %tb.so
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %tb.so --as-needed %ta.so -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+
+# RUN: ld.lld %t.o %tb.so --as-needed %ta.so --gc-sections -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s
+
+# The symbol a1 (defined in a.so) is not referenced by a regular object,
+# the reference to a2 is weak, don't add a DT_NEEDED entry for a.so.
+# CHECK-NOT: a.so
+
+# RUN: ld.lld %t.o %tb.so --as-needed %ta.so --no-as-needed %ta.so -o %t
+# RUN: llvm-readelf -d %t | FileCheck %s -check-prefix=NEEDED
+
+# a.so is needed because one of its occurrences is needed.
+# NEEDED: a.so
+
+.global _start
+.weak a2
+_start:
+ jmp b@PLT
+ jmp a2
diff --git a/test/ELF/as-needed-weak.s b/test/ELF/as-needed-weak.s
index f009c72d6f48..a47399a600c3 100644
--- a/test/ELF/as-needed-weak.s
+++ b/test/ELF/as-needed-weak.s
@@ -12,7 +12,7 @@
# 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@
+# CHECK-NEXT: 1 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo
.globl _start
.weak foo
diff --git a/test/ELF/bad-reloc-target.test b/test/ELF/bad-reloc-target.test
new file mode 100644
index 000000000000..fea8c5f0f396
--- /dev/null
+++ b/test/ELF/bad-reloc-target.test
@@ -0,0 +1,29 @@
+# RUN: yaml2obj %s -o %t1.o
+# RUN: not ld.lld %t1.o -o %t1 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}.o: unsupported relocation reference
+
+# RUN: yaml2obj %S/Inputs/bad-reloc-target.test -o %t2.o
+# RUN: not ld.lld %t2.o -o %t2 2>&1 | FileCheck %s --check-prefix=ERR2
+# ERR2: error: {{.*}}.o: invalid relocated section index: 99
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ Info: 0
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: foo
+ Type: R_X86_64_64
+Symbols:
+ Global:
+ - Name: foo \ No newline at end of file
diff --git a/test/ELF/basic-aarch64.s b/test/ELF/basic-aarch64.s
index efbe0080844f..151bf52cc3ee 100644
--- a/test/ELF/basic-aarch64.s
+++ b/test/ELF/basic-aarch64.s
@@ -59,7 +59,7 @@ _start:
# CHECK-NEXT: SHF_ALLOC (0x2)
# CHECK-NEXT: SHF_EXECINSTR (0x4)
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x20000
+# CHECK-NEXT: Address: 0x210000
# CHECK-NEXT: Offset: 0x10000
# CHECK-NEXT: Size: 12
# CHECK-NEXT: Link: 0
@@ -138,7 +138,7 @@ _start:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Name: $x.0
-# CHECK-NEXT: Value: 0x20000
+# CHECK-NEXT: Value: 0x210000
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
# CHECK-NEXT: Type: None (0x0)
@@ -159,8 +159,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_PHDR (0x6)
# CHECK-NEXT: Offset: 0x40
-# CHECK-NEXT: VirtualAddress: 0x10040
-# CHECK-NEXT: PhysicalAddress: 0x10040
+# CHECK-NEXT: VirtualAddress: 0x200040
+# CHECK-NEXT: PhysicalAddress: 0x200040
# CHECK-NEXT: FileSize: 224
# CHECK-NEXT: MemSize: 224
# CHECK-NEXT: Flags [ (0x4)
@@ -171,8 +171,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
# CHECK-NEXT: Offset: 0x0
-# CHECK-NEXT: VirtualAddress: 0x10000
-# CHECK-NEXT: PhysicalAddress: 0x10000
+# CHECK-NEXT: VirtualAddress: 0x200000
+# CHECK-NEXT: PhysicalAddress: 0x200000
# CHECK-NEXT: FileSize: 288
# CHECK-NEXT: MemSize: 288
# CHECK-NEXT: Flags [
@@ -183,8 +183,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
# CHECK-NEXT: Offset: 0x1000
-# CHECK-NEXT: VirtualAddress: 0x20000
-# CHECK-NEXT: PhysicalAddress: 0x20000
+# CHECK-NEXT: VirtualAddress: 0x210000
+# CHECK-NEXT: PhysicalAddress: 0x210000
# CHECK-NEXT: FileSize: 4096
# CHECK-NEXT: MemSize: 4096
# CHECK-NEXT: Flags [ (0x5)
diff --git a/test/ELF/basic-ppc64.s b/test/ELF/basic-ppc64.s
index f586d6320d16..624d8301cb63 100644
--- a/test/ELF/basic-ppc64.s
+++ b/test/ELF/basic-ppc64.s
@@ -28,7 +28,7 @@
// CHECK-NEXT: Version: 1
// CHECK-NEXT: Entry: 0x10000
// CHECK-NEXT: ProgramHeaderOffset: 0x40
-// CHECK-NEXT: SectionHeaderOffset:
+// CHECK-NEXT: SectionHeaderOffset: 0x200F8
// CHECK-NEXT: Flags [ (0x2)
// CHECK-NEXT: 0x2
// CHECK-NEXT: ]
@@ -36,8 +36,8 @@
// CHECK-NEXT: ProgramHeaderEntrySize: 56
// CHECK-NEXT: ProgramHeaderCount: 7
// CHECK-NEXT: SectionHeaderEntrySize: 64
-// CHECK-NEXT: SectionHeaderCount: 10
-// CHECK-NEXT: StringTableSectionIndex: 8
+// CHECK-NEXT: SectionHeaderCount: 11
+// CHECK-NEXT: StringTableSectionIndex: 9
// CHECK-NEXT:}
// CHECK-NEXT:Sections [
// CHECK-NEXT: Section {
@@ -156,7 +156,23 @@
// CHECK-NEXT: }
// CHECK-NEXT: Section {
// CHECK-NEXT: Index: 6
-// CHECK-NEXT: Name: .comment (38)
+// CHECK-NEXT: Name: .branch_lt (38)
+// CHECK-NEXT: Type: SHT_NOBITS (0x8)
+// CHECK-NEXT: Flags [ (0x3)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: SHF_WRITE (0x1)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x30000
+// CHECK-NEXT: Offset: 0x20060
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section {
+// CHECK-NEXT: Index: 7
+// CHECK-NEXT: Name: .comment (49)
// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
// CHECK-NEXT: Flags [ (0x30)
// CHECK-NEXT: SHF_MERGE (0x10)
@@ -174,15 +190,15 @@
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 7
-// CHECK-NEXT: Name: .symtab (47)
+// CHECK-NEXT: Index: 8
+// CHECK-NEXT: Name: .symtab (58)
// 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: Link: 10
// CHECK-NEXT: Info: 2
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 24
@@ -193,14 +209,14 @@
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 8
-// CHECK-NEXT: Name: .shstrtab (55)
+// CHECK-NEXT: Index: 9
+// CHECK-NEXT: Name: .shstrtab (66)
// 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: Size: 84
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
// CHECK-NEXT: AddressAlignment: 1
@@ -208,19 +224,20 @@
// 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: 0020: 6E616D69 63002E62 72616E63 685F6C74 |namic..branch_lt|
+// CHECK-NEXT: 0030: 002E636F 6D6D656E 74002E73 796D7461 |..comment..symta|
+// CHECK-NEXT: 0040: 62002E73 68737472 74616200 2E737472 |b..shstrtab..str|
+// CHECK-NEXT: 0050: 74616200 |tab.|
// CHECK-NEXT: )
// CHECK-NEXT: }
// CHECK-NEXT: Section {
-// CHECK-NEXT: Index: 9
-// CHECK-NEXT: Name: .strtab (65)
+// CHECK-NEXT: Index: 10
+// CHECK-NEXT: Name: .strtab (76)
// CHECK-NEXT: Type: SHT_STRTAB (0x3)
// CHECK-NEXT: Flags [ (0x0)
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x0
-// CHECK-NEXT: Offset: 0x200E1
+// CHECK-NEXT: Offset: 0x200EC
// CHECK-NEXT: Size: 10
// CHECK-NEXT: Link: 0
// CHECK-NEXT: Info: 0
@@ -275,7 +292,7 @@
// CHECK-NEXT: VirtualAddress: 0x20000
// CHECK-NEXT: PhysicalAddress: 0x20000
// CHECK-NEXT: FileSize: 96
-// CHECK-NEXT: MemSize: 96
+// CHECK-NEXT: MemSize: 65536
// CHECK-NEXT: Flags [ (0x6)
// CHECK-NEXT: PF_R (0x4)
// CHECK-NEXT: PF_W (0x2)
diff --git a/test/ELF/basic32.s b/test/ELF/basic32.s
index 72058dc6b168..38ef77959598 100644
--- a/test/ELF/basic32.s
+++ b/test/ELF/basic32.s
@@ -23,7 +23,7 @@ _start:
# CHECK-NEXT: Type: Executable (0x2)
# CHECK-NEXT: Machine: EM_386 (0x3)
# CHECK-NEXT: Version: 1
-# CHECK-NEXT: Entry: 0x11000
+# CHECK-NEXT: Entry: 0x401000
# CHECK-NEXT: ProgramHeaderOffset: 0x34
# CHECK-NEXT: SectionHeaderOffset: 0x205C
# CHECK-NEXT: Flags [ (0x0)
@@ -58,7 +58,7 @@ _start:
# CHECK-NEXT: SHF_ALLOC (0x2)
# CHECK-NEXT: SHF_EXECINSTR (0x4)
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x11000
+# CHECK-NEXT: Address: 0x401000
# CHECK-NEXT: Offset: 0x1000
# CHECK-NEXT: Size: 12
# CHECK-NEXT: Link: 0
@@ -129,8 +129,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_PHDR (0x6)
# CHECK-NEXT: Offset: 0x34
-# CHECK-NEXT: VirtualAddress: 0x10034
-# CHECK-NEXT: PhysicalAddress: 0x10034
+# CHECK-NEXT: VirtualAddress: 0x400034
+# CHECK-NEXT: PhysicalAddress: 0x400034
# CHECK-NEXT: FileSize: 128
# CHECK-NEXT: MemSize: 128
# CHECK-NEXT: Flags [ (0x4)
@@ -141,8 +141,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
# CHECK-NEXT: Offset: 0x0
-# CHECK-NEXT: VirtualAddress: 0x10000
-# CHECK-NEXT: PhysicalAddress: 0x10000
+# CHECK-NEXT: VirtualAddress: 0x400000
+# CHECK-NEXT: PhysicalAddress: 0x400000
# CHECK-NEXT: FileSize: 180
# CHECK-NEXT: MemSize: 180
# CHECK-NEXT: Flags [
@@ -153,8 +153,8 @@ _start:
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
# CHECK-NEXT: Offset: 0x1000
-# CHECK-NEXT: VirtualAddress: 0x11000
-# CHECK-NEXT: PhysicalAddress: 0x11000
+# CHECK-NEXT: VirtualAddress: 0x401000
+# CHECK-NEXT: PhysicalAddress: 0x401000
# CHECK-NEXT: FileSize: 4096
# CHECK-NEXT: MemSize: 4096
# CHECK-NEXT: Flags [ (0x5)
diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s
index 2bef1545153e..0add5b99bd57 100644
--- a/test/ELF/basic64be.s
+++ b/test/ELF/basic64be.s
@@ -23,7 +23,7 @@
# CHECK-NEXT: Version: 1
# CHECK-NEXT: Entry: 0x10010000
# CHECK-NEXT: ProgramHeaderOffset: 0x40
-# CHECK-NEXT: SectionHeaderOffset: 0x11050
+# CHECK-NEXT: SectionHeaderOffset: 0x20058
# CHECK-NEXT: Flags [ (0x2)
# CHECK-NEXT: 0x2
# CHECK-NEXT: ]
@@ -31,8 +31,8 @@
# CHECK-NEXT: ProgramHeaderEntrySize: 56
# CHECK-NEXT: ProgramHeaderCount: 4
# CHECK-NEXT: SectionHeaderEntrySize: 64
-# CHECK-NEXT: SectionHeaderCount: 6
-# CHECK-NEXT: StringTableSectionIndex: 4
+# CHECK-NEXT: SectionHeaderCount: 7
+# CHECK-NEXT: StringTableSectionIndex: 5
# CHECK-NEXT: }
# CHECK-NEXT: Sections [
# CHECK-NEXT: Section {
@@ -72,14 +72,32 @@
# CHECK-NEXT: }
# CHECK-NEXT: Section {
# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Name: .comment (7)
+# CHECK-NEXT: Name: .branch_lt (7)
+# 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: 0
+# CHECK-NEXT: Link: 0
+# CHECK-NEXT: Info: 0
+# CHECK-NEXT: AddressAlignment: 8
+# CHECK-NEXT: EntrySize: 0
+# CHECK-NEXT: SectionData (
+# CHECK-NEXT: )
+# CHECK-NEXT: }
+# CHECK-NEXT: Section {
+# CHECK-NEXT: Index: 3
+# CHECK-NEXT: Name: .comment (18)
# 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: 0x11000
+# CHECK-NEXT: Offset: 0x20000
# CHECK-NEXT: Size: 8
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
@@ -90,15 +108,15 @@
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 3
-# CHECK-NEXT: Name: .symtab (16)
+# CHECK-NEXT: Index: 4
+# CHECK-NEXT: Name: .symtab (27)
# CHECK-NEXT: Type: SHT_SYMTAB (0x2)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x11008
+# CHECK-NEXT: Offset: 0x20008
# CHECK-NEXT: Size: 24
-# CHECK-NEXT: Link: 5
+# CHECK-NEXT: Link: 6
# CHECK-NEXT: Info: 1
# CHECK-NEXT: AddressAlignment: 8
# CHECK-NEXT: EntrySize: 24
@@ -108,32 +126,33 @@
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 4
-# CHECK-NEXT: Name: .shstrtab (24)
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: Name: .shstrtab (35)
# CHECK-NEXT: Type: SHT_STRTAB (0x3)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x11020
-# CHECK-NEXT: Size: 42
+# CHECK-NEXT: Offset: 0x20020
+# CHECK-NEXT: Size: 53
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
# CHECK-NEXT: AddressAlignment: 1
# CHECK-NEXT: EntrySize: 0
# CHECK-NEXT: SectionData (
-# 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: 0000: 002E7465 7874002E 6272616E 63685F6C |..text..branch_l|
+# CHECK-NEXT: 0010: 74002E63 6F6D6D65 6E74002E 73796D74 |t..comment..symt|
+# CHECK-NEXT: 0020: 6162002E 73687374 72746162 002E7374 |ab..shstrtab..st|
+# CHECK-NEXT: 0030: 72746162 00 |rtab.|
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: Section {
-# CHECK-NEXT: Index: 5
-# CHECK-NEXT: Name: .strtab (34)
+# CHECK-NEXT: Index: 6
+# CHECK-NEXT: Name: .strtab (45)
# CHECK-NEXT: Type: SHT_STRTAB (0x3)
# CHECK-NEXT: Flags [ (0x0)
# CHECK-NEXT: ]
# CHECK-NEXT: Address: 0x0
-# CHECK-NEXT: Offset: 0x1104A
+# CHECK-NEXT: Offset: 0x20055
# CHECK-NEXT: Size: 1
# CHECK-NEXT: Link: 0
# CHECK-NEXT: Info: 0
@@ -150,8 +169,8 @@
# CHECK-NEXT: Offset: 0x40
# CHECK-NEXT: VirtualAddress: 0x10000040
# CHECK-NEXT: PhysicalAddress: 0x10000040
-# CHECK-NEXT: FileSize: 224
-# CHECK-NEXT: MemSize: 224
+# CHECK-NEXT: FileSize: 280
+# CHECK-NEXT: MemSize: 280
# CHECK-NEXT: Flags [ (0x4)
# CHECK-NEXT: PF_R (0x4)
# CHECK-NEXT: ]
@@ -162,8 +181,8 @@
# CHECK-NEXT: Offset: 0x0
# CHECK-NEXT: VirtualAddress: 0x10000000
# CHECK-NEXT: PhysicalAddress: 0x10000000
-# CHECK-NEXT: FileSize: 288
-# CHECK-NEXT: MemSize: 288
+# CHECK-NEXT: FileSize: 344
+# CHECK-NEXT: MemSize: 344
# CHECK-NEXT: Flags [ (0x4)
# CHECK-NEXT: PF_R (0x4)
# CHECK-NEXT: ]
diff --git a/test/ELF/bsymbolic-undef.s b/test/ELF/bsymbolic-undef.s
index 1269cb456228..97080273cf6c 100644
--- a/test/ELF/bsymbolic-undef.s
+++ b/test/ELF/bsymbolic-undef.s
@@ -5,7 +5,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -14,7 +14,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: undef@
+# CHECK-NEXT: Name: undef
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/cgprofile-obj.s b/test/ELF/cgprofile-obj.s
new file mode 100644
index 000000000000..4b7f465328cc
--- /dev/null
+++ b/test/ELF/cgprofile-obj.s
@@ -0,0 +1,44 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -e A %t.o -o %t
+# RUN: llvm-nm --no-sort %t | FileCheck %s
+# RUN: ld.lld --no-call-graph-profile-sort -e A %t.o -o %t
+# RUN: llvm-nm --no-sort %t | FileCheck %s --check-prefix=NO-CG
+
+ .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
+
+ .cg_profile A, B, 10
+ .cg_profile A, B, 10
+ .cg_profile Aa, B, 80
+ .cg_profile A, C, 40
+ .cg_profile B, C, 30
+ .cg_profile C, D, 90
+
+# CHECK: 0000000000201003 t D
+# CHECK: 0000000000201000 T A
+# CHECK: 0000000000201001 T B
+# CHECK: 0000000000201002 T C
+
+# NO-CG: 0000000000201000 t D
+# NO-CG: 0000000000201003 T A
+# NO-CG: 0000000000201002 T B
+# NO-CG: 0000000000201001 T C
diff --git a/test/ELF/cgprofile-shared-warn.s b/test/ELF/cgprofile-shared-warn.s
new file mode 100644
index 000000000000..86312770d1d7
--- /dev/null
+++ b/test/ELF/cgprofile-shared-warn.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --shared %t.o -o /dev/null 2>&1 | count 0
+# RUN: ld.lld -e A --unresolved-symbols=ignore-all %t.o -o /dev/null 2>&1 | count 0
+
+# RUN: echo '.globl B; B: ret' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o
+# RUN: ld.lld --shared %t1.o -o %t1.so
+# RUN: ld.lld -e A %t.o %t1.so -o /dev/null 2>&1 | count 0
+
+# RUN: ld.lld --gc-sections %t.o %t1.so -o /dev/null 2>&1 | count 0
+.globl _start
+_start:
+ ret
+
+.section .text.A,"ax",@progbits
+.globl A
+A:
+ callq B
+
+.cg_profile A, B, 10
diff --git a/test/ELF/cgprofile-txt2.s b/test/ELF/cgprofile-txt2.s
new file mode 100644
index 000000000000..e4f68524d2ac
--- /dev/null
+++ b/test/ELF/cgprofile-txt2.s
@@ -0,0 +1,38 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: echo "A B 5" > %t.call_graph
+# RUN: echo "B C 50" >> %t.call_graph
+# RUN: echo "C D 40" >> %t.call_graph
+# RUN: echo "D B 10" >> %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
+
+# CHECK: Name: A
+# CHECK-NEXT: Value: 0x201003
+# CHECK: Name: B
+# CHECK-NEXT: Value: 0x201000
+# CHECK: Name: C
+# CHECK-NEXT: Value: 0x201001
+# CHECK: Name: D
+# CHECK-NEXT: Value: 0x201002
+
+.section .text.A,"ax",@progbits
+.globl A
+A:
+ nop
+
+.section .text.B,"ax",@progbits
+.globl B
+B:
+ nop
+
+.section .text.C,"ax",@progbits
+.globl C
+C:
+ nop
+
+.section .text.D,"ax",@progbits
+.globl D
+D:
+ nop
diff --git a/test/ELF/common-gc2.s b/test/ELF/common-gc2.s
index 165bf625394e..21bff88b6181 100644
--- a/test/ELF/common-gc2.s
+++ b/test/ELF/common-gc2.s
@@ -3,8 +3,8 @@
# RUN: ld.lld -gc-sections -export-dynamic %t -o %t1
# RUN: llvm-readobj --dyn-symbols %t1 | FileCheck %s
-# CHECK: Name: bar@
-# CHECK: Name: foo@
+# CHECK: Name: bar
+# CHECK: Name: foo
.comm foo,4,4
.comm bar,4,4
diff --git a/test/ELF/compressed-debug-input-err.s b/test/ELF/compressed-debug-input-err.s
index e32ba315b342..191075e7c7c7 100644
--- a/test/ELF/compressed-debug-input-err.s
+++ b/test/ELF/compressed-debug-input-err.s
@@ -3,8 +3,8 @@
# 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
+## Check we are able to report zlib uncompress errors.
+# CHECK: error: {{.*}}.o:(.debug_str): uncompress failed: zlib error: Z_DATA_ERROR
.section .zdebug_str,"MS",@progbits,1
.ascii "ZLIB"
diff --git a/test/ELF/conflict.s b/test/ELF/conflict.s
index cbe1b5b8845a..6cfb8f557ad3 100644
--- a/test/ELF/conflict.s
+++ b/test/ELF/conflict.s
@@ -26,6 +26,7 @@
# RUN: FileCheck -check-prefix=DEMANGLE %s
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/conflict.s -o %t2.o
+# RUN: rm -f %t3.a
# RUN: llvm-ar rcs %t3.a %t2.o
# RUN: not ld.lld %t1.o %t3.a -u baz -o %t2 2>&1 | FileCheck -check-prefix=ARCHIVE %s
diff --git a/test/ELF/copy-rel-tls.s b/test/ELF/copy-rel-tls.s
new file mode 100644
index 000000000000..265cce1bc7a0
--- /dev/null
+++ b/test/ELF/copy-rel-tls.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-tls.s -o %t1.o
+// RUN: ld.lld %t1.o -shared -soname t1.so -o %t1.so
+// RUN: ld.lld %t.o %t1.so -o %t
+// RUN: llvm-nm %t1.so | FileCheck %s
+// RUN: llvm-nm %t | FileCheck --check-prefix=TLS %s
+// foo and tfoo have the same st_value but we should not copy tfoo.
+// CHECK: 2000 B foo
+// CHECK: 2000 B tfoo
+// TLS-NOT: tfoo
+
+.global _start
+_start:
+ leaq foo, %rax
diff --git a/test/ELF/debug-line-str.s b/test/ELF/debug-line-str.s
new file mode 100644
index 000000000000..e23b5c879291
--- /dev/null
+++ b/test/ELF/debug-line-str.s
@@ -0,0 +1,136 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -dwarf-version=5 %s -o %t.o
+# RUN: not ld.lld %t.o -o %t1 2>&1 | FileCheck %s
+
+# Check we do not crash and able to report the source location.
+
+# CHECK: error: undefined symbol: foo()
+# CHECK-NEXT: >>> referenced by test.cpp:3
+# CHECK-NEXT: >>> {{.*}}.o:(.text+0x1)
+
+# The code below is the reduced version of the output
+# from the following invocation and source:
+#
+# // test.cpp:
+# int foo();
+# int main() {
+# return foo();
+# }
+#
+# clang -gdwarf-5 test.cpp -o test.s -S
+# clang version 8.0.0 (trunk 343487)
+
+.text
+.file "test.cpp"
+.globl main
+.type main,@function
+main:
+.Lfunc_begin0:
+ .file 0 "/home/path" "test.cpp" md5 0x8ed32099ab837bd13543fd3e8102739f
+ .file 1 "test.cpp" md5 0x8ed32099ab837bd13543fd3e8102739f
+ .loc 1 3 10 prologue_end
+ jmp _Z3foov
+.Lfunc_end0:
+
+.Lstr_offsets_base0:
+.section .debug_str,"MS",@progbits,1
+ .asciz "stub"
+
+.section .debug_str_offsets,"",@progbits
+ .long 0
+
+.section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_yes
+ .byte 37 # DW_AT_producer
+ .byte 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+
+ .byte 3 # Abbreviation Code
+ .byte 36 # DW_TAG_base_type
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .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
+.Lcu_begin0:
+ .long 61 # Length of Unit
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+
+ .byte 1 # Abbrev [1] 0xc:0x35 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 0 # DW_AT_language
+ .byte 0 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long .Lline_table_start0 # DW_AT_stmt_list
+ .byte 0 # DW_AT_comp_dir
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+
+ .byte 2 # Abbrev [2] 0x26:0x16 DW_TAG_subprogram
+ .quad .Lfunc_begin0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 87
+ .byte 0 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 2 # DW_AT_decl_line
+ .long 60 # DW_AT_type
+ # DW_AT_external
+
+ .byte 3 # Abbrev [3] 0x3c:0x4 DW_TAG_base_type
+ .byte 0 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+
+.section .debug_line,"",@progbits
+.Lline_table_start0:
diff --git a/test/ELF/debug-relocation-none.test b/test/ELF/debug-relocation-none.test
new file mode 100644
index 000000000000..d22941db2220
--- /dev/null
+++ b/test/ELF/debug-relocation-none.test
@@ -0,0 +1,58 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+
+## Previously we would report an error saying the relocation in .debug_info
+## has an unsupported target.
+## Check we do not report debug information parsing errors when relocation
+## used is of type R_*_NONE, what actually means it should be ignored.
+
+# CHECK-NOT: error
+# CHECK: error: undefined symbol: bar
+# CHECK-NOT: error
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ Content: '0000000000000000'
+ - Name: .rela.text
+ Type: SHT_RELA
+ AddressAlign: 8
+ Link: .symtab
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: bar
+ Type: R_X86_64_64
+ - Name: .debug_line
+ Type: SHT_PROGBITS
+ Content: 3300000002001C0000000101FB0E0D000101010100000001000001006162632E7300000000000009020000000000000000140208000101
+ - Name: .rela.debug_line
+ AddressAlign: 8
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .debug_line
+ Relocations:
+ - Offset: 0x0000000000000029
+ Type: R_X86_64_NONE
+ - Name: .debug_info
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: 0C000000040000000000080100000000
+ - Name: .debug_abbrev
+ Type: SHT_PROGBITS
+ AddressAlign: 0x0000000000000001
+ Content: '0111001017000000'
+
+Symbols:
+ Global:
+ - Name: _start
+ Section: .text
+ - Name: bar
diff --git a/test/ELF/defsym.s b/test/ELF/defsym.s
index 2abc08f99dfc..598ecd51681f 100644
--- a/test/ELF/defsym.s
+++ b/test/ELF/defsym.s
@@ -9,6 +9,12 @@
# RUN: llvm-readobj -t -s %t2 | FileCheck %s
# RUN: llvm-objdump -d -print-imm-hex %t2 | FileCheck %s --check-prefix=USE
+## Check we are reporting the error correctly and don't crash
+## when handling the second --defsym.
+# RUN: not ld.lld -o %t2 %t.o --defsym ERR+ \
+# --defsym foo2=foo1 2>&1 | FileCheck %s --check-prefix=ERR
+# ERR: error: -defsym: syntax error: ERR+
+
# CHECK: Symbol {
# CHECK: Name: foo1
# CHECK-NEXT: Value: 0x123
@@ -68,8 +74,17 @@
# EXPR-NEXT: Section: Absolute
# EXPR-NEXT: }
-# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR
-# ERR: error: -defsym:1: symbol not found: und
+# RUN: not ld.lld -o %t %t.o --defsym=foo2=und 2>&1 | FileCheck %s -check-prefix=ERR1
+# ERR1: error: -defsym:1: symbol not found: und
+
+# RUN: not ld.lld -o %t %t.o --defsym=xxx=yyy,zzz 2>&1 | FileCheck %s -check-prefix=ERR2
+# ERR2: -defsym:1: EOF expected, but got ,
+
+# RUN: not ld.lld -o %t %t.o --defsym=foo 2>&1 | FileCheck %s -check-prefix=ERR3
+# ERR3: error: -defsym: syntax error: foo
+
+# RUN: not ld.lld -o %t %t.o --defsym= 2>&1 | FileCheck %s -check-prefix=ERR4
+# ERR4: error: -defsym: syntax error:
.globl foo1
foo1 = 0x123
diff --git a/test/ELF/dont-export-hidden.s b/test/ELF/dont-export-hidden.s
index 161e342bea84..651c024a03fe 100644
--- a/test/ELF/dont-export-hidden.s
+++ b/test/ELF/dont-export-hidden.s
@@ -19,7 +19,7 @@ foo:
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
diff --git a/test/ELF/driver-access.test b/test/ELF/driver-access.test
index 46b87c1f7e5d..da8fa6cd9de3 100644
--- a/test/ELF/driver-access.test
+++ b/test/ELF/driver-access.test
@@ -1,4 +1,4 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
# Make sure that LLD works even if the current directory is not writable.
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
diff --git a/test/ELF/driver.test b/test/ELF/driver.test
index 20bc79509725..585800a3b0b5 100644
--- a/test/ELF/driver.test
+++ b/test/ELF/driver.test
@@ -62,6 +62,9 @@
# RUN: not ld.lld %t -z foo 2>&1 | FileCheck -check-prefix=ERR10 %s
# ERR10: unknown -z value: foo
+## Check we report "unknown -z value" error even with -v.
+# RUN: not ld.lld %t -z foo -v 2>&1 | FileCheck -check-prefix=ERR10 %s
+
# RUN: not ld.lld %t -z max-page-size 2>&1 | FileCheck -check-prefix=ERR11 %s
# ERR11: unknown -z value: max-page-size
diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s
index e160e0600378..5f6addd0780a 100644
--- a/test/ELF/dt_flags.s
+++ b/test/ELF/dt_flags.s
@@ -3,7 +3,8 @@
# 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 initfirst -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1
+# RUN: ld.lld -z global -z initfirst -z interpose -z now -z nodefaultlib \
+# RUN: -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
@@ -14,7 +15,7 @@
# FLAGS: DynamicSection [
# FLAGS: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW
-# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE INITFIRST NOOPEN ORIGIN
+# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW GLOBAL NODELETE INITFIRST NOOPEN ORIGIN INTERPOSE NODEFLIB
# FLAGS: ]
# CHECK: DynamicSection [
diff --git a/test/ELF/dynamic-list-locals.s b/test/ELF/dynamic-list-locals.s
new file mode 100644
index 000000000000..36ac849f514d
--- /dev/null
+++ b/test/ELF/dynamic-list-locals.s
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "{ local: *; };" > %t.list
+# RUN: not ld.lld -dynamic-list %t.list -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}:1: "local:" scope not supported in --dynamic-list
diff --git a/test/ELF/dynamic-list-preempt.s b/test/ELF/dynamic-list-preempt.s
index 2bb10a3ed0a6..daed27a08f09 100644
--- a/test/ELF/dynamic-list-preempt.s
+++ b/test/ELF/dynamic-list-preempt.s
@@ -16,7 +16,7 @@
# DYNSYMS: DynamicSymbols [
# DYNSYMS-NEXT: Symbol {
-# DYNSYMS-NEXT: Name: @ (0)
+# DYNSYMS-NEXT: Name:
# DYNSYMS-NEXT: Value: 0x0
# DYNSYMS-NEXT: Size: 0
# DYNSYMS-NEXT: Binding: Local
@@ -25,7 +25,7 @@
# DYNSYMS-NEXT: Section: Undefined
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: Symbol {
-# DYNSYMS-NEXT: Name: bar@
+# DYNSYMS-NEXT: Name: bar
# DYNSYMS-NEXT: Value:
# DYNSYMS-NEXT: Size:
# DYNSYMS-NEXT: Binding: Global
@@ -34,7 +34,7 @@
# DYNSYMS-NEXT: Section:
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: Symbol {
-# DYNSYMS-NEXT: Name: ext@
+# DYNSYMS-NEXT: Name: ext
# DYNSYMS-NEXT: Value:
# DYNSYMS-NEXT: Size:
# DYNSYMS-NEXT: Binding: Global
@@ -43,7 +43,7 @@
# DYNSYMS-NEXT: Section:
# DYNSYMS-NEXT: }
# DYNSYMS-NEXT: Symbol {
-# DYNSYMS-NEXT: Name: foo@
+# DYNSYMS-NEXT: Name: foo
# DYNSYMS-NEXT: Value:
# DYNSYMS-NEXT: Size:
# DYNSYMS-NEXT: Binding: Global
diff --git a/test/ELF/dynamic-list-unexpected-end.s b/test/ELF/dynamic-list-unexpected-end.s
new file mode 100644
index 000000000000..f485a662dbf9
--- /dev/null
+++ b/test/ELF/dynamic-list-unexpected-end.s
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: echo "{ }; foo;" > %t.list
+# RUN: not ld.lld -dynamic-list %t.list -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}:1: EOF expected, but got foo
diff --git a/test/ELF/dynamic-list-wildcard.s b/test/ELF/dynamic-list-wildcard.s
index cd7ed71771ae..09a78af01a5a 100644
--- a/test/ELF/dynamic-list-wildcard.s
+++ b/test/ELF/dynamic-list-wildcard.s
@@ -8,7 +8,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -17,7 +17,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo1@ (1)
+# CHECK-NEXT: Name: foo1
# CHECK-NEXT: Value: 0x1000
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global (0x1)
@@ -26,7 +26,7 @@
# CHECK-NEXT: Section: .text (0x4)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo11@ (6)
+# CHECK-NEXT: Name: foo11
# CHECK-NEXT: Value: 0x1001
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/dynamic-list.s b/test/ELF/dynamic-list.s
index 888508e270a7..f6addcb9bf2e 100644
--- a/test/ELF/dynamic-list.s
+++ b/test/ELF/dynamic-list.s
@@ -23,7 +23,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
@@ -32,7 +32,7 @@
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo1@
+# CHECK-NEXT: Name: foo1
# CHECK-NEXT: Value: 0x201000
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global (0x1)
@@ -54,7 +54,7 @@
# CHECK2: DynamicSymbols [
# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: @
+# CHECK2-NEXT: Name:
# CHECK2-NEXT: Value: 0x0
# CHECK2-NEXT: Size: 0
# CHECK2-NEXT: Binding: Local
@@ -63,7 +63,7 @@
# CHECK2-NEXT: Section: Undefined
# CHECK2-NEXT: }
# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: foo1@
+# CHECK2-NEXT: Name: foo1
# CHECK2-NEXT: Value: 0x201000
# CHECK2-NEXT: Size: 0
# CHECK2-NEXT: Binding: Global (0x1)
@@ -72,7 +72,7 @@
# CHECK2-NEXT: Section: .text (0x4)
# CHECK2-NEXT: }
# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: foo2@
+# CHECK2-NEXT: Name: foo2
# CHECK2-NEXT: Value: 0x201001
# CHECK2-NEXT: Size: 0
# CHECK2-NEXT: Binding: Global (0x1)
@@ -81,7 +81,7 @@
# CHECK2-NEXT: Section: .text (0x4)
# CHECK2-NEXT: }
# CHECK2-NEXT: Symbol {
-# CHECK2-NEXT: Name: foo31@
+# CHECK2-NEXT: Name: foo31
# CHECK2-NEXT: Value: 0x201002
# CHECK2-NEXT: Size: 0
# CHECK2-NEXT: Binding: Global (0x1)
@@ -104,7 +104,7 @@
# CHECK3: DynamicSymbols [
# CHECK3-NEXT: Symbol {
-# CHECK3-NEXT: Name: @
+# CHECK3-NEXT: Name:
# CHECK3-NEXT: Value: 0x0
# CHECK3-NEXT: Size: 0
# CHECK3-NEXT: Binding: Local
@@ -113,7 +113,7 @@
# CHECK3-NEXT: Section: Undefined
# CHECK3-NEXT: }
# CHECK3-NEXT: Symbol {
-# CHECK3-NEXT: Name: _start@
+# CHECK3-NEXT: Name: _start
# CHECK3-NEXT: Value: 0x201003
# CHECK3-NEXT: Size: 0
# CHECK3-NEXT: Binding: Global (0x1)
@@ -122,7 +122,7 @@
# CHECK3-NEXT: Section: .text (0x4)
# CHECK3-NEXT: }
# CHECK3-NEXT: Symbol {
-# CHECK3-NEXT: Name: foo1@
+# CHECK3-NEXT: Name: foo1
# CHECK3-NEXT: Value: 0x201000
# CHECK3-NEXT: Size: 0
# CHECK3-NEXT: Binding: Global (0x1)
@@ -131,7 +131,7 @@
# CHECK3-NEXT: Section: .text (0x4)
# CHECK3-NEXT: }
# CHECK3-NEXT: Symbol {
-# CHECK3-NEXT: Name: foo2@
+# CHECK3-NEXT: Name: foo2
# CHECK3-NEXT: Value: 0x201001
# CHECK3-NEXT: Size: 0
# CHECK3-NEXT: Binding: Global (0x1)
@@ -140,7 +140,7 @@
# CHECK3-NEXT: Section: .text (0x4)
# CHECK3-NEXT: }
# CHECK3-NEXT: Symbol {
-# CHECK3-NEXT: Name: foo31@
+# CHECK3-NEXT: Name: foo31
# CHECK3-NEXT: Value: 0x201002
# CHECK3-NEXT: Size: 0
# CHECK3-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s
index 3a957ac0d05e..ce6d21c1b1e5 100644
--- a/test/ELF/dynamic-reloc.s
+++ b/test/ELF/dynamic-reloc.s
@@ -18,7 +18,7 @@
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: [[RELASIZE:.*]]
// CHECK-NEXT: Link: 1
-// CHECK-NEXT: Info: 0
+// CHECK-NEXT: Info: 7
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 24
diff --git a/test/ELF/dynsym-no-rosegment.s b/test/ELF/dynsym-no-rosegment.s
index 947f526e0575..c378bbce4afe 100644
--- a/test/ELF/dynsym-no-rosegment.s
+++ b/test/ELF/dynsym-no-rosegment.s
@@ -5,7 +5,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
@@ -14,7 +14,7 @@
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: undef@
+# CHECK-NEXT: Name: undef
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
diff --git a/test/ELF/dynsym-pie.s b/test/ELF/dynsym-pie.s
index b162d27335ac..6a7f4f1f0f70 100644
--- a/test/ELF/dynsym-pie.s
+++ b/test/ELF/dynsym-pie.s
@@ -50,7 +50,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
diff --git a/test/ELF/edata-etext.s b/test/ELF/edata-etext.s
index 52070cbc4ce3..6eef319f189e 100644
--- a/test/ELF/edata-etext.s
+++ b/test/ELF/edata-etext.s
@@ -18,7 +18,6 @@
# CHECK-NEXT: 2 .data 00000002 0000000000202000 DATA
# CHECK-NEXT: 3 .bss 00000006 0000000000202004 BSS
# CHECK: SYMBOL TABLE:
-# CHECK-NEXT: 0000000000000000 *UND* 00000000
# CHECK-NEXT: 0000000000202002 .data 00000000 _edata
# CHECK-NEXT: 000000000020200a .bss 00000000 _end
# CHECK-NEXT: 0000000000201001 .text 00000000 _etext
diff --git a/test/ELF/emit-relocs-icf1.s b/test/ELF/emit-relocs-icf1.s
new file mode 100644
index 000000000000..2f7e0cab27f6
--- /dev/null
+++ b/test/ELF/emit-relocs-icf1.s
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --emit-relocs --icf=all %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (3) .rela.text {
+# CHECK-NEXT: 0x201000 R_X86_64_64 .text 0x11
+# CHECK-NEXT: 0x201008 R_X86_64_64 .text 0x11
+# CHECK-NEXT: 0x201011 R_X86_64_64 .rodata 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.rodata
+quux:
+.quad 0xfe
+
+.section .text.foo,"ax"
+foo:
+.quad quux
+
+.section .text.bar,"ax"
+bar:
+.quad quux
+
+.text
+.quad foo
+.quad bar
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/emit-relocs-icf2.s b/test/ELF/emit-relocs-icf2.s
new file mode 100644
index 000000000000..7c9ac229b733
--- /dev/null
+++ b/test/ELF/emit-relocs-icf2.s
@@ -0,0 +1,36 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld --gc-sections --emit-relocs --icf=all %t.o -o %t
+# RUN: llvm-readobj -r %t | FileCheck %s
+
+# CHECK: Relocations [
+# CHECK-NEXT: Section (3) .rela.text {
+# CHECK-NEXT: 0x201000 R_X86_64_64 .text 0x11
+# CHECK-NEXT: 0x201008 R_X86_64_64 .text 0x11
+# CHECK-NEXT: 0x201011 R_X86_64_64 .rodata 0x0
+# CHECK-NEXT: }
+# CHECK-NEXT: ]
+
+.rodata
+quux:
+.quad 0xfe
+
+.section .text.foo,"ax"
+foo:
+.quad quux
+
+.section .text.bar,"ax"
+bar:
+.quad quux
+
+.section .text.baz,"ax"
+baz:
+.quad quux
+
+.text
+.quad foo
+.quad bar
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/empty-pack-dyn-relocs.s b/test/ELF/empty-pack-dyn-relocs.s
new file mode 100644
index 000000000000..b74a89d66d46
--- /dev/null
+++ b/test/ELF/empty-pack-dyn-relocs.s
@@ -0,0 +1,11 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.o -o %t
+// RUN: llvm-readobj -sections %t | FileCheck %s
+
+.global _start
+_start:
+ nop
+
+# CHECK-NOT: Name: .relr.dyn
diff --git a/test/ELF/empty-ver.s b/test/ELF/empty-ver.s
index 3412f3134737..d923607bfb01 100644
--- a/test/ELF/empty-ver.s
+++ b/test/ELF/empty-ver.s
@@ -29,7 +29,7 @@
// CHECK-NEXT: Symbols [
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Version: 0
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Version: 2
diff --git a/test/ELF/empty-ver2.s b/test/ELF/empty-ver2.s
index 2aceee128ba3..f4b288eb512c 100644
--- a/test/ELF/empty-ver2.s
+++ b/test/ELF/empty-ver2.s
@@ -8,11 +8,11 @@
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 1
-# CHECK-NEXT: Name: bar@@
+# CHECK-NEXT: Name: bar@
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/emulation-aarch64.s b/test/ELF/emulation-aarch64.s
new file mode 100644
index 000000000000..b9a6428fa953
--- /dev/null
+++ b/test/ELF/emulation-aarch64.s
@@ -0,0 +1,34 @@
+# REQUIRES: aarch64
+# 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 -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
+# RUN: echo 'OUTPUT_FORMAT(elf64-littleaarch64)' > %t4aarch64.script
+# RUN: ld.lld %t4aarch64.script %taarch64 -o %t4aarch64
+# RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s
+# AARCH64: ElfHeader {
+# AARCH64-NEXT: Ident {
+# AARCH64-NEXT: Magic: (7F 45 4C 46)
+# AARCH64-NEXT: Class: 64-bit (0x2)
+# AARCH64-NEXT: DataEncoding: LittleEndian (0x1)
+# AARCH64-NEXT: FileVersion: 1
+# AARCH64-NEXT: OS/ABI: SystemV (0x0)
+# AARCH64-NEXT: ABIVersion: 0
+# AARCH64-NEXT: Unused: (00 00 00 00 00 00 00)
+# AARCH64-NEXT: }
+# AARCH64-NEXT: Type: Executable (0x2)
+# AARCH64-NEXT: Machine: EM_AARCH64 (0xB7)
+# AARCH64-NEXT: Version: 1
+# AARCH64-NEXT: Entry:
+# AARCH64-NEXT: ProgramHeaderOffset: 0x40
+# AARCH64-NEXT: SectionHeaderOffset:
+# AARCH64-NEXT: Flags [ (0x0)
+# AARCH64-NEXT: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/emulation-arm.s b/test/ELF/emulation-arm.s
new file mode 100644
index 000000000000..53015e4701c8
--- /dev/null
+++ b/test/ELF/emulation-arm.s
@@ -0,0 +1,27 @@
+# REQUIRES: arm
+# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux %s -o %tarm
+# RUN: ld.lld -m armelf %tarm -o %t2arm
+# RUN: llvm-readobj -file-headers %t2arm | FileCheck --check-prefix=ARM %s
+# RUN: ld.lld -m armelf_linux_eabi %tarm -o %t3arm
+# RUN: llvm-readobj -file-headers %t3arm | FileCheck --check-prefix=ARM %s
+# RUN: ld.lld %tarm -o %t4arm
+# RUN: llvm-readobj -file-headers %t4arm | FileCheck --check-prefix=ARM %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-littlearm)' > %t5arm.script
+# RUN: ld.lld %t5arm.script %tarm -o %t5arm
+# RUN: llvm-readobj -file-headers %t5arm | FileCheck --check-prefix=ARM %s
+# ARM: ElfHeader {
+# ARM-NEXT: Ident {
+# ARM-NEXT: Magic: (7F 45 4C 46)
+# ARM-NEXT: Class: 32-bit (0x1)
+# ARM-NEXT: DataEncoding: LittleEndian (0x1)
+# ARM-NEXT: FileVersion: 1
+# ARM-NEXT: OS/ABI: SystemV (0x0)
+# ARM-NEXT: ABIVersion: 0
+# ARM-NEXT: Unused: (00 00 00 00 00 00 00)
+# ARM-NEXT: }
+# ARM-NEXT: Type: Executable (0x2)
+# ARM-NEXT: Machine: EM_ARM (0x28)
+# ARM-NEXT: Version: 1
+
+.globl _start
+_start:
diff --git a/test/ELF/emulation-mips.s b/test/ELF/emulation-mips.s
new file mode 100644
index 000000000000..42d0dd973eb3
--- /dev/null
+++ b/test/ELF/emulation-mips.s
@@ -0,0 +1,189 @@
+# REQUIRES: mips
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %tmips
+# RUN: ld.lld -m elf32btsmip -e _start %tmips -o %t2mips
+# RUN: llvm-readobj -file-headers %t2mips | FileCheck --check-prefix=MIPS %s
+# RUN: ld.lld %tmips -e _start -o %t3mips
+# RUN: llvm-readobj -file-headers %t3mips | FileCheck --check-prefix=MIPS %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-tradbigmips)' > %tmips.script
+# RUN: ld.lld %tmips.script -e _start %tmips -o %t4mips
+# RUN: llvm-readobj -file-headers %t4mips | FileCheck --check-prefix=MIPS %s
+# MIPS: ElfHeader {
+# MIPS-NEXT: Ident {
+# MIPS-NEXT: Magic: (7F 45 4C 46)
+# MIPS-NEXT: Class: 32-bit (0x1)
+# MIPS-NEXT: DataEncoding: BigEndian (0x2)
+# MIPS-NEXT: FileVersion: 1
+# MIPS-NEXT: OS/ABI: SystemV (0x0)
+# MIPS-NEXT: ABIVersion: 1
+# MIPS-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPS-NEXT: }
+# MIPS-NEXT: Type: Executable (0x2)
+# MIPS-NEXT: Machine: EM_MIPS (0x8)
+# MIPS-NEXT: Version: 1
+# MIPS-NEXT: Entry:
+# MIPS-NEXT: ProgramHeaderOffset: 0x34
+# MIPS-NEXT: SectionHeaderOffset:
+# MIPS-NEXT: Flags [
+# MIPS-NEXT: EF_MIPS_ABI_O32
+# MIPS-NEXT: EF_MIPS_ARCH_32
+# MIPS-NEXT: EF_MIPS_CPIC
+# MIPS-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %tmipsel
+# RUN: ld.lld -m elf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld -melf32ltsmip -e _start %tmipsel -o %t2mipsel
+# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: ld.lld %tmipsel -e _start -o %t3mipsel
+# RUN: llvm-readobj -file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-tradlittlemips)' > %tmipsel.script
+# RUN: ld.lld %tmipsel.script -e _start %tmipsel -o %t4mipsel
+# RUN: llvm-readobj -file-headers %t4mipsel | FileCheck --check-prefix=MIPSEL %s
+# MIPSEL: ElfHeader {
+# MIPSEL-NEXT: Ident {
+# MIPSEL-NEXT: Magic: (7F 45 4C 46)
+# MIPSEL-NEXT: Class: 32-bit (0x1)
+# MIPSEL-NEXT: DataEncoding: LittleEndian (0x1)
+# MIPSEL-NEXT: FileVersion: 1
+# MIPSEL-NEXT: OS/ABI: SystemV (0x0)
+# MIPSEL-NEXT: ABIVersion: 1
+# MIPSEL-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPSEL-NEXT: }
+# MIPSEL-NEXT: Type: Executable (0x2)
+# MIPSEL-NEXT: Machine: EM_MIPS (0x8)
+# MIPSEL-NEXT: Version: 1
+# MIPSEL-NEXT: Entry:
+# MIPSEL-NEXT: ProgramHeaderOffset: 0x34
+# MIPSEL-NEXT: SectionHeaderOffset:
+# MIPSEL-NEXT: Flags [
+# MIPSEL-NEXT: EF_MIPS_ABI_O32
+# MIPSEL-NEXT: EF_MIPS_ARCH_32
+# MIPSEL-NEXT: EF_MIPS_CPIC
+# MIPSEL-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux-gnuabin32 %s -o %tmipsn32
+# RUN: ld.lld -m elf32btsmipn32 -e _start %tmipsn32 -o %t2mipsn32
+# RUN: llvm-readobj -file-headers %t2mipsn32 | FileCheck --check-prefix=MIPSN32 %s
+# RUN: ld.lld %tmipsn32 -e _start -o %t3mipsn32
+# RUN: llvm-readobj -file-headers %t3mipsn32 | FileCheck --check-prefix=MIPSN32 %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-ntradbigmips)' > %tmipsn32.script
+# RUN: ld.lld %tmipsn32.script -e _start %tmipsn32 -o %t4mipsn32
+# RUN: llvm-readobj -file-headers %t4mipsn32 | FileCheck --check-prefix=MIPSN32 %s
+# MIPSN32: ElfHeader {
+# MIPSN32-NEXT: Ident {
+# MIPSN32-NEXT: Magic: (7F 45 4C 46)
+# MIPSN32-NEXT: Class: 32-bit (0x1)
+# MIPSN32-NEXT: DataEncoding: BigEndian (0x2)
+# MIPSN32-NEXT: FileVersion: 1
+# MIPSN32-NEXT: OS/ABI: SystemV (0x0)
+# MIPSN32-NEXT: ABIVersion: 1
+# MIPSN32-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPSN32-NEXT: }
+# MIPSN32-NEXT: Type: Executable (0x2)
+# MIPSN32-NEXT: Machine: EM_MIPS (0x8)
+# MIPSN32-NEXT: Version: 1
+# MIPSN32-NEXT: Entry:
+# MIPSN32-NEXT: ProgramHeaderOffset: 0x34
+# MIPSN32-NEXT: SectionHeaderOffset:
+# MIPSN32-NEXT: Flags [
+# MIPSN32-NEXT: EF_MIPS_ABI2
+# MIPSN32-NEXT: EF_MIPS_ARCH_64
+# MIPSN32-NEXT: EF_MIPS_CPIC
+# MIPSN32-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux-gnuabin32 %s -o %tmipsn32el
+# RUN: ld.lld -m elf32ltsmipn32 -e _start %tmipsn32el -o %t2mipsn32el
+# RUN: llvm-readobj -file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s
+# RUN: ld.lld -melf32ltsmipn32 -e _start %tmipsn32el -o %t2mipsn32el
+# RUN: llvm-readobj -file-headers %t2mipsn32el | FileCheck --check-prefix=MIPSN32EL %s
+# RUN: ld.lld %tmipsn32el -e _start -o %t3mipsn32el
+# RUN: llvm-readobj -file-headers %t3mipsn32el | FileCheck --check-prefix=MIPSN32EL %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-ntradlittlemips)' > %tmipsn32el.script
+# RUN: ld.lld %tmipsn32el.script -e _start %tmipsn32el -o %t4mipsn32el
+# RUN: llvm-readobj -file-headers %t4mipsn32el | FileCheck --check-prefix=MIPSN32EL %s
+# MIPSN32EL: ElfHeader {
+# MIPSN32EL-NEXT: Ident {
+# MIPSN32EL-NEXT: Magic: (7F 45 4C 46)
+# MIPSN32EL-NEXT: Class: 32-bit (0x1)
+# MIPSN32EL-NEXT: DataEncoding: LittleEndian (0x1)
+# MIPSN32EL-NEXT: FileVersion: 1
+# MIPSN32EL-NEXT: OS/ABI: SystemV (0x0)
+# MIPSN32EL-NEXT: ABIVersion: 1
+# MIPSN32EL-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPSN32EL-NEXT: }
+# MIPSN32EL-NEXT: Type: Executable (0x2)
+# MIPSN32EL-NEXT: Machine: EM_MIPS (0x8)
+# MIPSN32EL-NEXT: Version: 1
+# MIPSN32EL-NEXT: Entry:
+# MIPSN32EL-NEXT: ProgramHeaderOffset: 0x34
+# MIPSN32EL-NEXT: SectionHeaderOffset:
+# MIPSN32EL-NEXT: Flags [
+# MIPSN32EL-NEXT: EF_MIPS_ABI2
+# MIPSN32EL-NEXT: EF_MIPS_ARCH_64
+# MIPSN32EL-NEXT: EF_MIPS_CPIC
+# MIPSN32EL-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -position-independent \
+# RUN: %s -o %tmips64
+# RUN: ld.lld -m elf64btsmip -e _start %tmips64 -o %t2mips64
+# RUN: llvm-readobj -file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s
+# RUN: ld.lld %tmips64 -e _start -o %t3mips64
+# RUN: llvm-readobj -file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s
+# RUN: echo 'OUTPUT_FORMAT(elf64-tradbigmips)' > %tmips64.script
+# RUN: ld.lld %tmips64.script -e _start %tmips64 -o %t4mips64
+# RUN: llvm-readobj -file-headers %t4mips64 | FileCheck --check-prefix=MIPS64 %s
+# MIPS64: ElfHeader {
+# MIPS64-NEXT: Ident {
+# MIPS64-NEXT: Magic: (7F 45 4C 46)
+# MIPS64-NEXT: Class: 64-bit (0x2)
+# MIPS64-NEXT: DataEncoding: BigEndian (0x2)
+# MIPS64-NEXT: FileVersion: 1
+# MIPS64-NEXT: OS/ABI: SystemV (0x0)
+# MIPS64-NEXT: ABIVersion: 0
+# MIPS64-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPS64-NEXT: }
+# MIPS64-NEXT: Type: Executable (0x2)
+# MIPS64-NEXT: Machine: EM_MIPS (0x8)
+# MIPS64-NEXT: Version: 1
+# MIPS64-NEXT: Entry:
+# MIPS64-NEXT: ProgramHeaderOffset: 0x40
+# MIPS64-NEXT: SectionHeaderOffset:
+# MIPS64-NEXT: Flags [
+# MIPS64-NEXT: EF_MIPS_ARCH_64
+# MIPS64-NEXT: EF_MIPS_CPIC
+# MIPS64-NEXT: EF_MIPS_PIC
+# MIPS64-NEXT: ]
+
+# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \
+# RUN: -position-independent %s -o %tmips64el
+# RUN: ld.lld -m elf64ltsmip -e _start %tmips64el -o %t2mips64el
+# RUN: llvm-readobj -file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s
+# RUN: ld.lld %tmips64el -e _start -o %t3mips64el
+# RUN: llvm-readobj -file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s
+# RUN: echo 'OUTPUT_FORMAT(elf64-tradlittlemips)' > %tmips64el.script
+# RUN: ld.lld %tmips64el.script -e _start %tmips64el -o %t4mips64el
+# RUN: llvm-readobj -file-headers %t4mips64el | FileCheck --check-prefix=MIPS64EL %s
+# MIPS64EL: ElfHeader {
+# MIPS64EL-NEXT: Ident {
+# MIPS64EL-NEXT: Magic: (7F 45 4C 46)
+# MIPS64EL-NEXT: Class: 64-bit (0x2)
+# MIPS64EL-NEXT: DataEncoding: LittleEndian (0x1)
+# MIPS64EL-NEXT: FileVersion: 1
+# MIPS64EL-NEXT: OS/ABI: SystemV (0x0)
+# MIPS64EL-NEXT: ABIVersion: 0
+# MIPS64EL-NEXT: Unused: (00 00 00 00 00 00 00)
+# MIPS64EL-NEXT: }
+# MIPS64EL-NEXT: Type: Executable (0x2)
+# MIPS64EL-NEXT: Machine: EM_MIPS (0x8)
+# MIPS64EL-NEXT: Version: 1
+# MIPS64EL-NEXT: Entry:
+# MIPS64EL-NEXT: ProgramHeaderOffset: 0x40
+# MIPS64EL-NEXT: SectionHeaderOffset:
+# MIPS64EL-NEXT: Flags [
+# MIPS64EL-NEXT: EF_MIPS_ARCH_64
+# MIPS64EL-NEXT: EF_MIPS_CPIC
+# MIPS64EL-NEXT: EF_MIPS_PIC
+# MIPS64EL-NEXT: ]
+
+.globl _start
+_start:
diff --git a/test/ELF/emulation-ppc.s b/test/ELF/emulation-ppc.s
new file mode 100644
index 000000000000..12e84782252f
--- /dev/null
+++ b/test/ELF/emulation-ppc.s
@@ -0,0 +1,75 @@
+# REQUIRES: ppc
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64
+# RUN: ld.lld -m elf64ppc %tppc64 -o %t2ppc64
+# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s
+# RUN: ld.lld %tppc64 -o %t3ppc64
+# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s
+# RUN: echo 'OUTPUT_FORMAT(elf64-powerpc)' > %tppc64.script
+# RUN: ld.lld %tppc64.script %tppc64 -o %t4ppc64
+# RUN: llvm-readobj -file-headers %t4ppc64 | FileCheck --check-prefix=PPC64 %s
+
+# PPC64: ElfHeader {
+# PPC64-NEXT: Ident {
+# PPC64-NEXT: Magic: (7F 45 4C 46)
+# PPC64-NEXT: Class: 64-bit (0x2)
+# PPC64-NEXT: DataEncoding: BigEndian (0x2)
+# PPC64-NEXT: FileVersion: 1
+# PPC64-NEXT: OS/ABI: SystemV (0x0)
+# PPC64-NEXT: ABIVersion: 0
+# PPC64-NEXT: Unused: (00 00 00 00 00 00 00)
+# PPC64-NEXT: }
+# PPC64-NEXT: Type: Executable (0x2)
+# PPC64-NEXT: Machine: EM_PPC64 (0x15)
+# PPC64-NEXT: Version: 1
+# PPC64-NEXT: Entry:
+# PPC64-NEXT: ProgramHeaderOffset: 0x40
+# PPC64-NEXT: SectionHeaderOffset:
+# PPC64-NEXT: Flags [ (0x2)
+# PPC64-NEXT: 0x2
+# PPC64-NEXT: ]
+# PPC64-NEXT: HeaderSize: 64
+# PPC64-NEXT: ProgramHeaderEntrySize: 56
+# PPC64-NEXT: ProgramHeaderCount:
+# PPC64-NEXT: SectionHeaderEntrySize: 64
+# PPC64-NEXT: SectionHeaderCount:
+# PPC64-NEXT: StringTableSectionIndex:
+# PPC64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=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
+# RUN: echo 'OUTPUT_FORMAT(elf64-powerpcle)' > %tppc64le.script
+# RUN: ld.lld %tppc64le.script %tppc64le -o %t4ppc64le
+# RUN: llvm-readobj -file-headers %t4ppc64le | 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: }
+
+.globl _start
+_start:
diff --git a/test/ELF/emulation-x86.s b/test/ELF/emulation-x86.s
new file mode 100644
index 000000000000..65d807c67f2f
--- /dev/null
+++ b/test/ELF/emulation-x86.s
@@ -0,0 +1,205 @@
+# REQUIRES: x86
+# 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
+# RUN: ld.lld %tx64 -o %t3x64
+# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=AMD64 %s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.sysv
+# RUN: ld.lld -m elf_amd64_fbsd %t.sysv -o %t.freebsd
+# RUN: llvm-readobj -file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s
+# AMD64: ElfHeader {
+# AMD64-NEXT: Ident {
+# AMD64-NEXT: Magic: (7F 45 4C 46)
+# AMD64-NEXT: Class: 64-bit (0x2)
+# AMD64-NEXT: DataEncoding: LittleEndian (0x1)
+# AMD64-NEXT: FileVersion: 1
+# AMD64-NEXT: OS/ABI: FreeBSD (0x9)
+# AMD64-NEXT: ABIVersion: 0
+# AMD64-NEXT: Unused: (00 00 00 00 00 00 00)
+# AMD64-NEXT: }
+# AMD64-NEXT: Type: Executable (0x2)
+# AMD64-NEXT: Machine: EM_X86_64 (0x3E)
+# AMD64-NEXT: Version: 1
+# AMD64-NEXT: Entry:
+# AMD64-NEXT: ProgramHeaderOffset: 0x40
+# AMD64-NEXT: SectionHeaderOffset:
+# AMD64-NEXT: Flags [ (0x0)
+# AMD64-NEXT: ]
+# AMD64-NEXT: HeaderSize: 64
+# AMD64-NEXT: ProgramHeaderEntrySize: 56
+# AMD64-NEXT: ProgramHeaderCount:
+# AMD64-NEXT: SectionHeaderEntrySize: 64
+# AMD64-NEXT: SectionHeaderCount:
+# AMD64-NEXT: StringTableSectionIndex:
+# AMD64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64
+# RUN: ld.lld -m elf_x86_64 %tx64 -o %t2x64
+# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
+# RUN: ld.lld %tx64 -o %t3x64
+# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
+# RUN: echo 'OUTPUT_FORMAT(elf64-x86-64)' > %t4x64.script
+# RUN: ld.lld %t4x64.script %tx64 -o %t4x64
+# RUN: ld.lld %tx64 -o %t4x64 %t4x64.script
+# RUN: llvm-readobj -file-headers %t4x64 | FileCheck --check-prefix=X86-64 %s
+# X86-64: ElfHeader {
+# X86-64-NEXT: Ident {
+# X86-64-NEXT: Magic: (7F 45 4C 46)
+# X86-64-NEXT: Class: 64-bit (0x2)
+# X86-64-NEXT: DataEncoding: LittleEndian (0x1)
+# X86-64-NEXT: FileVersion: 1
+# X86-64-NEXT: OS/ABI: SystemV (0x0)
+# X86-64-NEXT: ABIVersion: 0
+# X86-64-NEXT: Unused: (00 00 00 00 00 00 00)
+# X86-64-NEXT: }
+# X86-64-NEXT: Type: Executable (0x2)
+# X86-64-NEXT: Machine: EM_X86_64 (0x3E)
+# X86-64-NEXT: Version: 1
+# X86-64-NEXT: Entry:
+# X86-64-NEXT: ProgramHeaderOffset: 0x40
+# X86-64-NEXT: SectionHeaderOffset:
+# X86-64-NEXT: Flags [ (0x0)
+# X86-64-NEXT: ]
+# X86-64-NEXT: HeaderSize: 64
+# X86-64-NEXT: ProgramHeaderEntrySize: 56
+# X86-64-NEXT: ProgramHeaderCount:
+# X86-64-NEXT: SectionHeaderEntrySize: 64
+# X86-64-NEXT: SectionHeaderCount:
+# X86-64-NEXT: StringTableSectionIndex:
+# X86-64-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnux32 %s -o %tx32
+# RUN: ld.lld -m elf32_x86_64 %tx32 -o %t2x32
+# RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s
+# RUN: ld.lld %tx32 -o %t3x32
+# RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-x86-64)' > %t4x32.script
+# RUN: ld.lld %t4x32.script %tx32 -o %t4x32
+# RUN: llvm-readobj -file-headers %t4x32 | FileCheck --check-prefix=X32 %s
+# X32: ElfHeader {
+# X32-NEXT: Ident {
+# X32-NEXT: Magic: (7F 45 4C 46)
+# X32-NEXT: Class: 32-bit (0x1)
+# X32-NEXT: DataEncoding: LittleEndian (0x1)
+# X32-NEXT: FileVersion: 1
+# X32-NEXT: OS/ABI: SystemV (0x0)
+# X32-NEXT: ABIVersion: 0
+# X32-NEXT: Unused: (00 00 00 00 00 00 00)
+# X32-NEXT: }
+# X32-NEXT: Type: Executable (0x2)
+# X32-NEXT: Machine: EM_X86_64 (0x3E)
+# X32-NEXT: Version: 1
+# X32-NEXT: Entry:
+# X32-NEXT: ProgramHeaderOffset: 0x34
+# X32-NEXT: SectionHeaderOffset:
+# X32-NEXT: Flags [ (0x0)
+# X32-NEXT: ]
+# X32-NEXT: HeaderSize: 52
+# X32-NEXT: ProgramHeaderEntrySize: 32
+# X32-NEXT: ProgramHeaderCount:
+# X32-NEXT: SectionHeaderEntrySize: 40
+# X32-NEXT: SectionHeaderCount:
+# X32-NEXT: StringTableSectionIndex:
+# X32-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86
+# RUN: ld.lld -m elf_i386 %tx86 -o %t2x86
+# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
+# RUN: ld.lld %tx86 -o %t3x86
+# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-i386)' > %t4x86.script
+# RUN: ld.lld %t4x86.script %tx86 -o %t4x86
+# RUN: llvm-readobj -file-headers %t4x86 | FileCheck --check-prefix=X86 %s
+# X86: ElfHeader {
+# X86-NEXT: Ident {
+# X86-NEXT: Magic: (7F 45 4C 46)
+# X86-NEXT: Class: 32-bit (0x1)
+# X86-NEXT: DataEncoding: LittleEndian (0x1)
+# X86-NEXT: FileVersion: 1
+# X86-NEXT: OS/ABI: SystemV (0x0)
+# X86-NEXT: ABIVersion: 0
+# X86-NEXT: Unused: (00 00 00 00 00 00 00)
+# X86-NEXT: }
+# X86-NEXT: Type: Executable (0x2)
+# X86-NEXT: Machine: EM_386 (0x3)
+# X86-NEXT: Version: 1
+# X86-NEXT: Entry:
+# X86-NEXT: ProgramHeaderOffset: 0x34
+# X86-NEXT: SectionHeaderOffset:
+# X86-NEXT: Flags [ (0x0)
+# X86-NEXT: ]
+# X86-NEXT: HeaderSize: 52
+# X86-NEXT: ProgramHeaderEntrySize: 32
+# X86-NEXT: ProgramHeaderCount:
+# X86-NEXT: SectionHeaderEntrySize: 40
+# X86-NEXT: SectionHeaderCount:
+# X86-NEXT: StringTableSectionIndex:
+# X86-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd
+# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86_fbsd
+# RUN: llvm-readobj -file-headers %t2x86_fbsd | FileCheck --check-prefix=X86FBSD %s
+# RUN: ld.lld %tx86fbsd -o %t3x86fbsd
+# RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s
+# X86FBSD: ElfHeader {
+# X86FBSD-NEXT: Ident {
+# X86FBSD-NEXT: Magic: (7F 45 4C 46)
+# X86FBSD-NEXT: Class: 32-bit (0x1)
+# X86FBSD-NEXT: DataEncoding: LittleEndian (0x1)
+# X86FBSD-NEXT: FileVersion: 1
+# X86FBSD-NEXT: OS/ABI: FreeBSD (0x9)
+# X86FBSD-NEXT: ABIVersion: 0
+# X86FBSD-NEXT: Unused: (00 00 00 00 00 00 00)
+# X86FBSD-NEXT: }
+# X86FBSD-NEXT: Type: Executable (0x2)
+# X86FBSD-NEXT: Machine: EM_386 (0x3)
+# X86FBSD-NEXT: Version: 1
+# X86FBSD-NEXT: Entry:
+# X86FBSD-NEXT: ProgramHeaderOffset: 0x34
+# X86FBSD-NEXT: SectionHeaderOffset:
+# X86FBSD-NEXT: Flags [ (0x0)
+# X86FBSD-NEXT: ]
+# X86FBSD-NEXT: HeaderSize: 52
+# X86FBSD-NEXT: ProgramHeaderEntrySize: 32
+# X86FBSD-NEXT: ProgramHeaderCount:
+# X86FBSD-NEXT: SectionHeaderEntrySize: 40
+# X86FBSD-NEXT: SectionHeaderCount:
+# X86FBSD-NEXT: StringTableSectionIndex:
+# X86FBSD-NEXT: }
+
+# RUN: llvm-mc -filetype=obj -triple=i586-intel-elfiamcu %s -o %tiamcu
+# RUN: ld.lld -m elf_iamcu %tiamcu -o %t2iamcu
+# RUN: llvm-readobj -file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s
+# RUN: ld.lld %tiamcu -o %t3iamcu
+# RUN: llvm-readobj -file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s
+# RUN: echo 'OUTPUT_FORMAT(elf32-iamcu)' > %t4iamcu.script
+# RUN: ld.lld %t4iamcu.script %tiamcu -o %t4iamcu
+# RUN: llvm-readobj -file-headers %t4iamcu | FileCheck --check-prefix=IAMCU %s
+# IAMCU: ElfHeader {
+# IAMCU-NEXT: Ident {
+# IAMCU-NEXT: Magic: (7F 45 4C 46)
+# IAMCU-NEXT: Class: 32-bit (0x1)
+# IAMCU-NEXT: DataEncoding: LittleEndian (0x1)
+# IAMCU-NEXT: FileVersion: 1
+# IAMCU-NEXT: OS/ABI: SystemV (0x0)
+# IAMCU-NEXT: ABIVersion: 0
+# IAMCU-NEXT: Unused: (00 00 00 00 00 00 00)
+# IAMCU-NEXT: }
+# IAMCU-NEXT: Type: Executable (0x2)
+# IAMCU-NEXT: Machine: EM_IAMCU (0x6)
+# IAMCU-NEXT: Version: 1
+# IAMCU-NEXT: Entry:
+# IAMCU-NEXT: ProgramHeaderOffset: 0x34
+# IAMCU-NEXT: SectionHeaderOffset:
+# IAMCU-NEXT: Flags [ (0x0)
+# IAMCU-NEXT: ]
+# IAMCU-NEXT: HeaderSize: 52
+# IAMCU-NEXT: ProgramHeaderEntrySize: 32
+# IAMCU-NEXT: ProgramHeaderCount:
+# IAMCU-NEXT: SectionHeaderEntrySize: 40
+# IAMCU-NEXT: SectionHeaderCount:
+# IAMCU-NEXT: StringTableSectionIndex:
+# IAMCU-NEXT: }
+
+.globl _start
+_start:
diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s
deleted file mode 100644
index 98f78b8ec1df..000000000000
--- a/test/ELF/emulation.s
+++ /dev/null
@@ -1,396 +0,0 @@
-# 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
-# RUN: ld.lld %tx64 -o %t3x64
-# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=AMD64 %s
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.sysv
-# RUN: ld.lld -m elf_amd64_fbsd %t.sysv -o %t.freebsd
-# RUN: llvm-readobj -file-headers %t.freebsd | FileCheck --check-prefix=AMD64 %s
-# AMD64: ElfHeader {
-# AMD64-NEXT: Ident {
-# AMD64-NEXT: Magic: (7F 45 4C 46)
-# AMD64-NEXT: Class: 64-bit (0x2)
-# AMD64-NEXT: DataEncoding: LittleEndian (0x1)
-# AMD64-NEXT: FileVersion: 1
-# AMD64-NEXT: OS/ABI: FreeBSD (0x9)
-# AMD64-NEXT: ABIVersion: 0
-# AMD64-NEXT: Unused: (00 00 00 00 00 00 00)
-# AMD64-NEXT: }
-# AMD64-NEXT: Type: Executable (0x2)
-# AMD64-NEXT: Machine: EM_X86_64 (0x3E)
-# AMD64-NEXT: Version: 1
-# AMD64-NEXT: Entry:
-# AMD64-NEXT: ProgramHeaderOffset: 0x40
-# AMD64-NEXT: SectionHeaderOffset:
-# AMD64-NEXT: Flags [ (0x0)
-# AMD64-NEXT: ]
-# AMD64-NEXT: HeaderSize: 64
-# AMD64-NEXT: ProgramHeaderEntrySize: 56
-# AMD64-NEXT: ProgramHeaderCount:
-# AMD64-NEXT: SectionHeaderEntrySize: 64
-# AMD64-NEXT: SectionHeaderCount:
-# AMD64-NEXT: StringTableSectionIndex:
-# AMD64-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx64
-# RUN: ld.lld -m elf_x86_64 %tx64 -o %t2x64
-# RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=X86-64 %s
-# RUN: ld.lld %tx64 -o %t3x64
-# RUN: llvm-readobj -file-headers %t3x64 | FileCheck --check-prefix=X86-64 %s
-# X86-64: ElfHeader {
-# X86-64-NEXT: Ident {
-# X86-64-NEXT: Magic: (7F 45 4C 46)
-# X86-64-NEXT: Class: 64-bit (0x2)
-# X86-64-NEXT: DataEncoding: LittleEndian (0x1)
-# X86-64-NEXT: FileVersion: 1
-# X86-64-NEXT: OS/ABI: SystemV (0x0)
-# X86-64-NEXT: ABIVersion: 0
-# X86-64-NEXT: Unused: (00 00 00 00 00 00 00)
-# X86-64-NEXT: }
-# X86-64-NEXT: Type: Executable (0x2)
-# X86-64-NEXT: Machine: EM_X86_64 (0x3E)
-# X86-64-NEXT: Version: 1
-# X86-64-NEXT: Entry:
-# X86-64-NEXT: ProgramHeaderOffset: 0x40
-# X86-64-NEXT: SectionHeaderOffset:
-# X86-64-NEXT: Flags [ (0x0)
-# X86-64-NEXT: ]
-# X86-64-NEXT: HeaderSize: 64
-# X86-64-NEXT: ProgramHeaderEntrySize: 56
-# X86-64-NEXT: ProgramHeaderCount:
-# X86-64-NEXT: SectionHeaderEntrySize: 64
-# X86-64-NEXT: SectionHeaderCount:
-# X86-64-NEXT: StringTableSectionIndex:
-# X86-64-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnux32 %s -o %tx32
-# RUN: ld.lld -m elf32_x86_64 %tx32 -o %t2x32
-# RUN: llvm-readobj -file-headers %t2x32 | FileCheck --check-prefix=X32 %s
-# RUN: ld.lld %tx32 -o %t3x32
-# RUN: llvm-readobj -file-headers %t3x32 | FileCheck --check-prefix=X32 %s
-# X32: ElfHeader {
-# X32-NEXT: Ident {
-# X32-NEXT: Magic: (7F 45 4C 46)
-# X32-NEXT: Class: 32-bit (0x1)
-# X32-NEXT: DataEncoding: LittleEndian (0x1)
-# X32-NEXT: FileVersion: 1
-# X32-NEXT: OS/ABI: SystemV (0x0)
-# X32-NEXT: ABIVersion: 0
-# X32-NEXT: Unused: (00 00 00 00 00 00 00)
-# X32-NEXT: }
-# X32-NEXT: Type: Executable (0x2)
-# X32-NEXT: Machine: EM_X86_64 (0x3E)
-# X32-NEXT: Version: 1
-# X32-NEXT: Entry:
-# X32-NEXT: ProgramHeaderOffset: 0x34
-# X32-NEXT: SectionHeaderOffset:
-# X32-NEXT: Flags [ (0x0)
-# X32-NEXT: ]
-# X32-NEXT: HeaderSize: 52
-# X32-NEXT: ProgramHeaderEntrySize: 32
-# X32-NEXT: ProgramHeaderCount:
-# X32-NEXT: SectionHeaderEntrySize: 40
-# X32-NEXT: SectionHeaderCount:
-# X32-NEXT: StringTableSectionIndex:
-# X32-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tx86
-# RUN: ld.lld -m elf_i386 %tx86 -o %t2x86
-# RUN: llvm-readobj -file-headers %t2x86 | FileCheck --check-prefix=X86 %s
-# RUN: ld.lld %tx86 -o %t3x86
-# RUN: llvm-readobj -file-headers %t3x86 | FileCheck --check-prefix=X86 %s
-# X86: ElfHeader {
-# X86-NEXT: Ident {
-# X86-NEXT: Magic: (7F 45 4C 46)
-# X86-NEXT: Class: 32-bit (0x1)
-# X86-NEXT: DataEncoding: LittleEndian (0x1)
-# X86-NEXT: FileVersion: 1
-# X86-NEXT: OS/ABI: SystemV (0x0)
-# X86-NEXT: ABIVersion: 0
-# X86-NEXT: Unused: (00 00 00 00 00 00 00)
-# X86-NEXT: }
-# X86-NEXT: Type: Executable (0x2)
-# X86-NEXT: Machine: EM_386 (0x3)
-# X86-NEXT: Version: 1
-# X86-NEXT: Entry:
-# X86-NEXT: ProgramHeaderOffset: 0x34
-# X86-NEXT: SectionHeaderOffset:
-# X86-NEXT: Flags [ (0x0)
-# X86-NEXT: ]
-# X86-NEXT: HeaderSize: 52
-# X86-NEXT: ProgramHeaderEntrySize: 32
-# X86-NEXT: ProgramHeaderCount:
-# X86-NEXT: SectionHeaderEntrySize: 40
-# X86-NEXT: SectionHeaderCount:
-# X86-NEXT: StringTableSectionIndex:
-# X86-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=i686-unknown-freebsd %s -o %tx86fbsd
-# RUN: ld.lld -m elf_i386_fbsd %tx86fbsd -o %t2x86_fbsd
-# RUN: llvm-readobj -file-headers %t2x86_fbsd | FileCheck --check-prefix=X86FBSD %s
-# RUN: ld.lld %tx86fbsd -o %t3x86fbsd
-# RUN: llvm-readobj -file-headers %t3x86fbsd | FileCheck --check-prefix=X86FBSD %s
-# X86FBSD: ElfHeader {
-# X86FBSD-NEXT: Ident {
-# X86FBSD-NEXT: Magic: (7F 45 4C 46)
-# X86FBSD-NEXT: Class: 32-bit (0x1)
-# X86FBSD-NEXT: DataEncoding: LittleEndian (0x1)
-# X86FBSD-NEXT: FileVersion: 1
-# X86FBSD-NEXT: OS/ABI: FreeBSD (0x9)
-# X86FBSD-NEXT: ABIVersion: 0
-# X86FBSD-NEXT: Unused: (00 00 00 00 00 00 00)
-# X86FBSD-NEXT: }
-# X86FBSD-NEXT: Type: Executable (0x2)
-# X86FBSD-NEXT: Machine: EM_386 (0x3)
-# X86FBSD-NEXT: Version: 1
-# X86FBSD-NEXT: Entry:
-# X86FBSD-NEXT: ProgramHeaderOffset: 0x34
-# X86FBSD-NEXT: SectionHeaderOffset:
-# X86FBSD-NEXT: Flags [ (0x0)
-# X86FBSD-NEXT: ]
-# X86FBSD-NEXT: HeaderSize: 52
-# X86FBSD-NEXT: ProgramHeaderEntrySize: 32
-# X86FBSD-NEXT: ProgramHeaderCount:
-# X86FBSD-NEXT: SectionHeaderEntrySize: 40
-# X86FBSD-NEXT: SectionHeaderCount:
-# X86FBSD-NEXT: StringTableSectionIndex:
-# X86FBSD-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=i586-intel-elfiamcu %s -o %tiamcu
-# RUN: ld.lld -m elf_iamcu %tiamcu -o %t2iamcu
-# RUN: llvm-readobj -file-headers %t2iamcu | FileCheck --check-prefix=IAMCU %s
-# RUN: ld.lld %tiamcu -o %t3iamcu
-# RUN: llvm-readobj -file-headers %t3iamcu | FileCheck --check-prefix=IAMCU %s
-# IAMCU: ElfHeader {
-# IAMCU-NEXT: Ident {
-# IAMCU-NEXT: Magic: (7F 45 4C 46)
-# IAMCU-NEXT: Class: 32-bit (0x1)
-# IAMCU-NEXT: DataEncoding: LittleEndian (0x1)
-# IAMCU-NEXT: FileVersion: 1
-# IAMCU-NEXT: OS/ABI: SystemV (0x0)
-# IAMCU-NEXT: ABIVersion: 0
-# IAMCU-NEXT: Unused: (00 00 00 00 00 00 00)
-# IAMCU-NEXT: }
-# IAMCU-NEXT: Type: Executable (0x2)
-# IAMCU-NEXT: Machine: EM_IAMCU (0x6)
-# IAMCU-NEXT: Version: 1
-# IAMCU-NEXT: Entry:
-# IAMCU-NEXT: ProgramHeaderOffset: 0x34
-# IAMCU-NEXT: SectionHeaderOffset:
-# IAMCU-NEXT: Flags [ (0x0)
-# IAMCU-NEXT: ]
-# IAMCU-NEXT: HeaderSize: 52
-# IAMCU-NEXT: ProgramHeaderEntrySize: 32
-# IAMCU-NEXT: ProgramHeaderCount:
-# IAMCU-NEXT: SectionHeaderEntrySize: 40
-# IAMCU-NEXT: SectionHeaderCount:
-# IAMCU-NEXT: StringTableSectionIndex:
-# IAMCU-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %tppc64
-# RUN: ld.lld -m elf64ppc %tppc64 -o %t2ppc64
-# RUN: llvm-readobj -file-headers %t2ppc64 | FileCheck --check-prefix=PPC64 %s
-# RUN: ld.lld %tppc64 -o %t3ppc64
-# RUN: llvm-readobj -file-headers %t3ppc64 | FileCheck --check-prefix=PPC64 %s
-# PPC64: ElfHeader {
-# PPC64-NEXT: Ident {
-# PPC64-NEXT: Magic: (7F 45 4C 46)
-# PPC64-NEXT: Class: 64-bit (0x2)
-# PPC64-NEXT: DataEncoding: BigEndian (0x2)
-# PPC64-NEXT: FileVersion: 1
-# PPC64-NEXT: OS/ABI: SystemV (0x0)
-# PPC64-NEXT: ABIVersion: 0
-# PPC64-NEXT: Unused: (00 00 00 00 00 00 00)
-# PPC64-NEXT: }
-# PPC64-NEXT: Type: Executable (0x2)
-# PPC64-NEXT: Machine: EM_PPC64 (0x15)
-# PPC64-NEXT: Version: 1
-# PPC64-NEXT: Entry:
-# PPC64-NEXT: ProgramHeaderOffset: 0x40
-# PPC64-NEXT: SectionHeaderOffset:
-# PPC64-NEXT: Flags [ (0x2)
-# PPC64-NEXT: 0x2
-# PPC64-NEXT: ]
-# PPC64-NEXT: HeaderSize: 64
-# PPC64-NEXT: ProgramHeaderEntrySize: 56
-# PPC64-NEXT: ProgramHeaderCount:
-# PPC64-NEXT: SectionHeaderEntrySize: 64
-# PPC64-NEXT: SectionHeaderCount:
-# PPC64-NEXT: StringTableSectionIndex:
-# PPC64-NEXT: }
-
-# RUN: llvm-mc -filetype=obj -triple=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
-# RUN: ld.lld %tmips -e _start -o %t3mips
-# RUN: llvm-readobj -file-headers %t3mips | FileCheck --check-prefix=MIPS %s
-# MIPS: ElfHeader {
-# MIPS-NEXT: Ident {
-# MIPS-NEXT: Magic: (7F 45 4C 46)
-# MIPS-NEXT: Class: 32-bit (0x1)
-# MIPS-NEXT: DataEncoding: BigEndian (0x2)
-# MIPS-NEXT: FileVersion: 1
-# MIPS-NEXT: OS/ABI: SystemV (0x0)
-# MIPS-NEXT: ABIVersion: 1
-# MIPS-NEXT: Unused: (00 00 00 00 00 00 00)
-# MIPS-NEXT: }
-# MIPS-NEXT: Type: Executable (0x2)
-# MIPS-NEXT: Machine: EM_MIPS (0x8)
-# MIPS-NEXT: Version: 1
-# MIPS-NEXT: Entry:
-# MIPS-NEXT: ProgramHeaderOffset: 0x34
-# MIPS-NEXT: SectionHeaderOffset:
-# MIPS-NEXT: Flags [
-# MIPS-NEXT: EF_MIPS_ABI_O32
-# MIPS-NEXT: EF_MIPS_ARCH_32
-# MIPS-NEXT: EF_MIPS_CPIC
-# MIPS-NEXT: ]
-
-# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %tmipsel
-# RUN: ld.lld -m elf32ltsmip -e _start %tmipsel -o %t2mipsel
-# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
-# RUN: ld.lld -melf32ltsmip -e _start %tmipsel -o %t2mipsel
-# RUN: llvm-readobj -file-headers %t2mipsel | FileCheck --check-prefix=MIPSEL %s
-# RUN: ld.lld %tmipsel -e _start -o %t3mipsel
-# RUN: llvm-readobj -file-headers %t3mipsel | FileCheck --check-prefix=MIPSEL %s
-# MIPSEL: ElfHeader {
-# MIPSEL-NEXT: Ident {
-# MIPSEL-NEXT: Magic: (7F 45 4C 46)
-# MIPSEL-NEXT: Class: 32-bit (0x1)
-# MIPSEL-NEXT: DataEncoding: LittleEndian (0x1)
-# MIPSEL-NEXT: FileVersion: 1
-# MIPSEL-NEXT: OS/ABI: SystemV (0x0)
-# MIPSEL-NEXT: ABIVersion: 1
-# MIPSEL-NEXT: Unused: (00 00 00 00 00 00 00)
-# MIPSEL-NEXT: }
-# MIPSEL-NEXT: Type: Executable (0x2)
-# MIPSEL-NEXT: Machine: EM_MIPS (0x8)
-# MIPSEL-NEXT: Version: 1
-# MIPSEL-NEXT: Entry:
-# MIPSEL-NEXT: ProgramHeaderOffset: 0x34
-# MIPSEL-NEXT: SectionHeaderOffset:
-# MIPSEL-NEXT: Flags [
-# MIPSEL-NEXT: EF_MIPS_ABI_O32
-# MIPSEL-NEXT: EF_MIPS_ARCH_32
-# MIPSEL-NEXT: EF_MIPS_CPIC
-# MIPSEL-NEXT: ]
-
-# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -position-independent \
-# RUN: %s -o %tmips64
-# RUN: ld.lld -m elf64btsmip -e _start %tmips64 -o %t2mips64
-# RUN: llvm-readobj -file-headers %t2mips64 | FileCheck --check-prefix=MIPS64 %s
-# RUN: ld.lld %tmips64 -e _start -o %t3mips64
-# RUN: llvm-readobj -file-headers %t3mips64 | FileCheck --check-prefix=MIPS64 %s
-# MIPS64: ElfHeader {
-# MIPS64-NEXT: Ident {
-# MIPS64-NEXT: Magic: (7F 45 4C 46)
-# MIPS64-NEXT: Class: 64-bit (0x2)
-# MIPS64-NEXT: DataEncoding: BigEndian (0x2)
-# MIPS64-NEXT: FileVersion: 1
-# MIPS64-NEXT: OS/ABI: SystemV (0x0)
-# MIPS64-NEXT: ABIVersion: 0
-# MIPS64-NEXT: Unused: (00 00 00 00 00 00 00)
-# MIPS64-NEXT: }
-# MIPS64-NEXT: Type: Executable (0x2)
-# MIPS64-NEXT: Machine: EM_MIPS (0x8)
-# MIPS64-NEXT: Version: 1
-# MIPS64-NEXT: Entry:
-# MIPS64-NEXT: ProgramHeaderOffset: 0x40
-# MIPS64-NEXT: SectionHeaderOffset:
-# MIPS64-NEXT: Flags [
-# MIPS64-NEXT: EF_MIPS_ARCH_64
-# MIPS64-NEXT: EF_MIPS_CPIC
-# MIPS64-NEXT: EF_MIPS_PIC
-# MIPS64-NEXT: ]
-
-# RUN: llvm-mc -filetype=obj -triple=mips64el-unknown-linux \
-# RUN: -position-independent %s -o %tmips64el
-# RUN: ld.lld -m elf64ltsmip -e _start %tmips64el -o %t2mips64el
-# RUN: llvm-readobj -file-headers %t2mips64el | FileCheck --check-prefix=MIPS64EL %s
-# RUN: ld.lld %tmips64el -e _start -o %t3mips64el
-# RUN: llvm-readobj -file-headers %t3mips64el | FileCheck --check-prefix=MIPS64EL %s
-# MIPS64EL: ElfHeader {
-# MIPS64EL-NEXT: Ident {
-# MIPS64EL-NEXT: Magic: (7F 45 4C 46)
-# MIPS64EL-NEXT: Class: 64-bit (0x2)
-# MIPS64EL-NEXT: DataEncoding: LittleEndian (0x1)
-# MIPS64EL-NEXT: FileVersion: 1
-# MIPS64EL-NEXT: OS/ABI: SystemV (0x0)
-# MIPS64EL-NEXT: ABIVersion: 0
-# MIPS64EL-NEXT: Unused: (00 00 00 00 00 00 00)
-# MIPS64EL-NEXT: }
-# MIPS64EL-NEXT: Type: Executable (0x2)
-# MIPS64EL-NEXT: Machine: EM_MIPS (0x8)
-# MIPS64EL-NEXT: Version: 1
-# MIPS64EL-NEXT: Entry:
-# MIPS64EL-NEXT: ProgramHeaderOffset: 0x40
-# MIPS64EL-NEXT: SectionHeaderOffset:
-# MIPS64EL-NEXT: Flags [
-# MIPS64EL-NEXT: EF_MIPS_ARCH_64
-# MIPS64EL-NEXT: EF_MIPS_CPIC
-# MIPS64EL-NEXT: EF_MIPS_PIC
-# MIPS64EL-NEXT: ]
-
-# RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64
-# RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64
-# RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s
-# RUN: ld.lld -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)
-# AARCH64-NEXT: Class: 64-bit (0x2)
-# AARCH64-NEXT: DataEncoding: LittleEndian (0x1)
-# AARCH64-NEXT: FileVersion: 1
-# AARCH64-NEXT: OS/ABI: SystemV (0x0)
-# AARCH64-NEXT: ABIVersion: 0
-# AARCH64-NEXT: Unused: (00 00 00 00 00 00 00)
-# AARCH64-NEXT: }
-# AARCH64-NEXT: Type: Executable (0x2)
-# AARCH64-NEXT: Machine: EM_AARCH64 (0xB7)
-# AARCH64-NEXT: Version: 1
-# AARCH64-NEXT: Entry:
-# AARCH64-NEXT: ProgramHeaderOffset: 0x40
-# AARCH64-NEXT: SectionHeaderOffset:
-# AARCH64-NEXT: Flags [ (0x0)
-# AARCH64-NEXT: ]
-
-.globl _start
-_start:
diff --git a/test/ELF/execute-only-mixed-data.s b/test/ELF/execute-only-mixed-data.s
index 6ef62368123f..b57695493dd6 100644
--- a/test/ELF/execute-only-mixed-data.s
+++ b/test/ELF/execute-only-mixed-data.s
@@ -16,7 +16,7 @@
// RUN: }" > %t.lds
// RUN: ld.lld -T%t.lds %t.o -o %t -execute-only 2>&1
-// CHECK: -execute-only does not support intermingling data and code
+// CHECK: cannot place {{.*}}:(.rodata.foo) into .text: -execute-only does not support intermingling data and code
br lr
diff --git a/test/ELF/format-binary.test b/test/ELF/format-binary.test
index 94b9b51afe78..7c554bb60e43 100644
--- a/test/ELF/format-binary.test
+++ b/test/ELF/format-binary.test
@@ -55,3 +55,15 @@
# CHECK-NEXT: Other: 0
# CHECK-NEXT: Section: Absolute
# CHECK-NEXT: }
+
+# RUN: echo 'OUTPUT_FORMAT(elf64-x86-64)' > %t.script
+# RUN: ld.lld -b binary %t.binary -T %t.script -o %t.out
+# RUN: llvm-readobj %t.out -sections -section-data -symbols | FileCheck -check-prefix=X86-64 %s
+
+# X86-64: Format: ELF64-x86-64
+
+# RUN: echo 'OUTPUT_FORMAT("elf64-x86-64")' > %t.script
+# RUN: ld.lld -b binary %t.binary -T %t.script -o %t.out
+# RUN: llvm-readobj %t.out -sections -section-data -symbols | FileCheck -check-prefix=X86-64-in-quotes %s
+
+# X86-64-in-quotes: Format: ELF64-x86-64
diff --git a/test/ELF/gc-sections-implicit-addend.s b/test/ELF/gc-sections-implicit-addend.s
index 1270affbcc0e..e3bdeaac1d7f 100644
--- a/test/ELF/gc-sections-implicit-addend.s
+++ b/test/ELF/gc-sections-implicit-addend.s
@@ -12,10 +12,10 @@
# CHECK-NEXT: SHF_MERGE
# CHECK-NEXT: SHF_STRINGS
# CHECK-NEXT: ]
-# CHECK-NEXT: Address: 0x100B4
+# CHECK-NEXT: Address: 0x4000B4
-# 0x100B4 == 65716
-# DISASM: leal 65716, %eax
+# 0x4000B4 == 4194484
+# DISASM: leal 4194484, %eax
.section .foo,"aMS",@progbits,1
.byte 0
diff --git a/test/ELF/gc-sections-linker-defined-symbol.s b/test/ELF/gc-sections-linker-defined-symbol.s
index 796f7b363559..e570116e31e1 100644
--- a/test/ELF/gc-sections-linker-defined-symbol.s
+++ b/test/ELF/gc-sections-linker-defined-symbol.s
@@ -4,7 +4,7 @@
# RUN: ld.lld %t.o -o %t.so --gc-sections -shared
# RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s
-# CHECK: Name: _end@
+# CHECK: Name: _end
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding: Global
diff --git a/test/ELF/gdb-index-base-addr.s b/test/ELF/gdb-index-base-addr.s
index 3871f8fc92e9..a16ea7b2c9dc 100644
--- a/test/ELF/gdb-index-base-addr.s
+++ b/test/ELF/gdb-index-base-addr.s
@@ -3,7 +3,7 @@
# RUN: ld.lld --gdb-index %t1.o -o %t
# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
-# CHECK: .gnu_index contents:
+# CHECK: .gdb_index contents:
# CHECK: Address area offset = 0x28, has 2 entries:
# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
# CHECK-NEXT: Low/High address = [0x201003, 0x201006) (Size: 0x3), CU id = 0
diff --git a/test/ELF/gdb-index-dwarf5-low-high.s b/test/ELF/gdb-index-dwarf5-low-high.s
new file mode 100644
index 000000000000..94b713c6d216
--- /dev/null
+++ b/test/ELF/gdb-index-dwarf5-low-high.s
@@ -0,0 +1,49 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld --gdb-index %t.o -o %t
+# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
+
+# CHECK: Address area offset = 0x28, has 1 entries:
+# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+
+ .text
+ .globl main
+main: # @main
+.Lfunc_begin0:
+ retq
+.Lfunc_end0:
+ .section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_no
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0 # EOM(3)
+
+ .section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+ .byte 1 # Abbrev [1] 0xc:0x2b DW_TAG_compile_unit
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+.Ldebug_info_end0:
+
+ .section .debug_addr,"",@progbits
+ .long 12
+ .short 5
+ .byte 8
+ .byte 0
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
diff --git a/test/ELF/gdb-index-invalid-ranges.s b/test/ELF/gdb-index-invalid-ranges.s
new file mode 100644
index 000000000000..1aac98d87cf6
--- /dev/null
+++ b/test/ELF/gdb-index-invalid-ranges.s
@@ -0,0 +1,42 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld --gdb-index -e main %t.o -o %t 2>&1 | FileCheck %s
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gdb-index-invalid-ranges.obj.s -o %t2.o
+# RUN: llvm-ar rc %t.a %t.o
+# RUN: not ld.lld --gdb-index -e main %t2.o %t.a -o %t 2>&1 | FileCheck --check-prefix=ARCHIVE %s
+
+# CHECK: ld.lld: error: {{.*}}gdb-index-invalid-ranges.s.tmp.o:(.debug_info): decoding address ranges: invalid range list entry at offset 0x10
+# ARCHIVE: ld.lld: error: {{.*}}gdb-index-invalid-ranges.s.tmp.a(gdb-index-invalid-ranges.s.tmp.o):(.debug_info): decoding address ranges: invalid range list entry at offset 0x10
+
+.section .text.foo1,"ax",@progbits
+.globl f1
+.Lfunc_begin0:
+f1:
+ nop
+.Lfunc_end0:
+
+.section .debug_abbrev,"",@progbits
+.byte 1 # Abbreviation Code
+.byte 17 # DW_TAG_compile_unit
+.byte 0 # DW_CHILDREN_no
+.byte 85 # DW_AT_ranges
+.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 .Lunit_end0-.Lunit_begin0 # Length of Unit
+.Lunit_begin0:
+.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 .Ldebug_ranges0 # DW_AT_ranges
+.Lunit_end0:
+
+.section .debug_ranges,"",@progbits
+.Ldebug_ranges0:
+.quad .Lfunc_begin0
+.quad .Lfunc_end0
diff --git a/test/ELF/gdb-index-multiple-cu-2.s b/test/ELF/gdb-index-multiple-cu-2.s
new file mode 100644
index 000000000000..9cf2a0c82693
--- /dev/null
+++ b/test/ELF/gdb-index-multiple-cu-2.s
@@ -0,0 +1,36 @@
+# 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/gdb-index-multiple-cu-2.s -o %t1.o
+# RUN: ld.lld --gdb-index %t.o %t1.o -o %t
+# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
+
+# %t.o has 2 CUs while %t1 has 1, thus _start in %t1.o should have CuIndex 2.
+# Attributes << 24 | CuIndex = 48 << 24 | 2 = 0x30000002
+# CHECK: Constant pool
+# CHECK-NEXT: 0(0x0): 0x30000002
+
+.section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 0 # DW_CHILDREN_yes
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0
+
+.section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Lcu_end0 - .Lcu_begin0 - 4
+ .short 4 # DWARF version number
+ .long 0 # Offset Into Abbrev. Section
+ .byte 4 # Address Size
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 0
+.Lcu_end0:
+.Lcu_begin1:
+ .long .Lcu_end1 - .Lcu_begin1 - 4
+ .short 4 # DWARF version number
+ .long 0 # Offset Into Abbrev. Section
+ .byte 4 # Address Size
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 0
+.Lcu_end1:
diff --git a/test/ELF/gdb-index-multiple-cu.s b/test/ELF/gdb-index-multiple-cu.s
new file mode 100644
index 000000000000..9a8c2eae78d4
--- /dev/null
+++ b/test/ELF/gdb-index-multiple-cu.s
@@ -0,0 +1,88 @@
+# 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
+
+# CuIndexAndAttrs of _start:
+# Attributes << 24 | CuIndex = 48 << 24 | 0 = 0x30000000
+# CuIndexAndAttrs of foo:
+# Attributes << 24 | CuIndex = 48 << 24 | 1 = 0x30000001
+# CHECK: Symbol table
+# CHECK-DAG: String name: _start, CU vector index: 0
+# CHECK-DAG: String name: foo, CU vector index: 1
+# CHECK: Constant pool
+# CHECK-NEXT: 0(0x0): 0x30000000
+# CHECK-NEXT: 1(0x8): 0x30000001
+
+.globl _start, foo
+_start:
+foo:
+
+.section .debug_abbrev,"",@progbits
+ .byte 1 # Abbreviation Code
+ .byte 17 # DW_TAG_compile_unit
+ .byte 1 # DW_CHILDREN_yes
+ .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 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 3 # DW_AT_name
+ .byte 8 # DW_FORM_string
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 0
+
+.section .debug_info,"",@progbits
+.Lcu_begin0:
+ .long .Lcu_end0 - .Lcu_begin0 - 4
+ .short 4 # DWARF version number
+ .long 0 # Offset Into Abbrev. Section
+ .byte 4 # Address Size
+.Ldie0:
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 2 # Abbrev [2] DW_TAG_subprogram
+ .asciz "_start" # DW_AT_name
+ .byte 0
+ .byte 0
+.Lcu_end0:
+.Lcu_begin1:
+ .long .Lcu_end1 - .Lcu_begin1 - 4
+ .short 4 # DWARF version number
+ .long 0 # Offset Into Abbrev. Section
+ .byte 4 # Address Size
+.Ldie1:
+ .byte 1 # Abbrev [1] DW_TAG_compile_unit
+ .byte 2 # Abbrev [2] DW_TAG_subprogram
+ .asciz "foo" # DW_AT_name
+ .byte 0
+.Lcu_end1:
+
+# Swap sets to test the case where pubnames are in a
+# different order than the CUs they refer to.
+.section .debug_gnu_pubnames,"",@progbits
+ # CuIndex: 1
+ .long .LpubNames_end1 - .LpubNames_begin1
+.LpubNames_begin1:
+ .short 2 # Version
+ .long .Lcu_begin1 # CU Offset
+ .long .Lcu_end1 - .Lcu_begin1
+ .long .Ldie1 - .Lcu_begin1
+ .byte 48 # Attributes: FUNCTION, EXTERNAL
+ .asciz "foo" # External Name
+ .long 0
+.LpubNames_end1:
+
+ # CuIndex: 0
+ .long .LpubNames_end0 - .LpubNames_begin0
+.LpubNames_begin0:
+ .short 2 # Version
+ .long .Lcu_begin0 # CU Offset
+ .long .Lcu_end0 - .Lcu_begin0
+ .long .Ldie0 - .Lcu_begin0
+ .byte 48 # Attributes: FUNCTION, EXTERNAL
+ .asciz "_start" # External Name
+ .long 0
+.LpubNames_end0:
diff --git a/test/ELF/gdb-index-no-debug.s b/test/ELF/gdb-index-no-debug.s
new file mode 100644
index 000000000000..dba5fcf26385
--- /dev/null
+++ b/test/ELF/gdb-index-no-debug.s
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld -o %t.exe -gdb-index %t.o
+# RUN: llvm-objdump --section-headers %t.exe | FileCheck %s
+# CHECK-NOT: .gdb_index
+
+.global _start
+_start:
diff --git a/test/ELF/gdb-index-ranges.s b/test/ELF/gdb-index-ranges.s
index c41be114f005..2190a2442f52 100644
--- a/test/ELF/gdb-index-ranges.s
+++ b/test/ELF/gdb-index-ranges.s
@@ -3,7 +3,7 @@
# RUN: ld.lld --gdb-index -e main %t.o -o %t
# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
-# CHECK: .gnu_index contents:
+# CHECK: .gdb_index contents:
# CHECK: Address area offset = 0x28, has 2 entries:
# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
# CHECK-NEXT: Low/High address = [0x201001, 0x201003) (Size: 0x2), CU id = 0
diff --git a/test/ELF/gdb-index-rng-lists.s b/test/ELF/gdb-index-rng-lists.s
new file mode 100644
index 000000000000..d853d3bb6052
--- /dev/null
+++ b/test/ELF/gdb-index-rng-lists.s
@@ -0,0 +1,202 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
+# RUN: ld.lld --gdb-index %t1.o -o %t
+# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s
+
+## The code contains DWARF v5 sections .debug_rnglists and .debug_addr.
+## Check we are able to build the correct address
+## area using address range lists.
+
+# CHECK: .gdb_index contents:
+# CHECK: Address area offset = 0x28, has 2 entries:
+# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0
+# CHECK-NEXT: Low/High address = [0x201001, 0x201003) (Size: 0x2), CU id = 0
+
+.text
+.section .text._Z3zedv,"ax",@progbits
+.Lfunc_begin0:
+ retq
+.Lfunc_end0:
+
+.section .text.main,"ax",@progbits
+.Lfunc_begin1:
+ retq
+ retq
+.Lfunc_end1:
+
+.section .debug_str_offsets,"",@progbits
+.long 32
+.short 5
+.short 0
+.Lstr_offsets_base0:
+ .long .Linfo_string0
+ .long .Linfo_string0
+ .long .Linfo_string0
+ .long .Linfo_string0
+ .long .Linfo_string0
+ .long .Linfo_string0
+ .long .Linfo_string0
+
+.section .debug_str,"MS",@progbits,1
+.Linfo_string0:
+ .asciz "stub"
+
+.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 37 # DW_FORM_strx1
+ .byte 19 # DW_AT_language
+ .byte 5 # DW_FORM_data2
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 114 # DW_AT_str_offsets_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 16 # DW_AT_stmt_list
+ .byte 23 # DW_FORM_sec_offset
+ .byte 27 # DW_AT_comp_dir
+ .byte 37 # DW_FORM_strx1
+ .byte 115 # DW_AT_addr_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 17 # DW_AT_low_pc
+ .byte 1 # DW_FORM_addr
+ .byte 85 # DW_AT_ranges
+ .byte 35 # DW_FORM_rnglistx
+ .byte 116 # DW_AT_rnglists_base
+ .byte 23 # DW_FORM_sec_offset
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 2 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 110 # DW_AT_linkage_name
+ .byte 37 # DW_FORM_strx1
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .byte 0 # EOM(1)
+ .byte 0 # EOM(2)
+ .byte 3 # Abbreviation Code
+ .byte 46 # DW_TAG_subprogram
+ .byte 0 # DW_CHILDREN_no
+ .byte 17 # DW_AT_low_pc
+ .byte 27 # DW_FORM_addrx
+ .byte 18 # DW_AT_high_pc
+ .byte 6 # DW_FORM_data4
+ .byte 64 # DW_AT_frame_base
+ .byte 24 # DW_FORM_exprloc
+ .byte 3 # DW_AT_name
+ .byte 37 # DW_FORM_strx1
+ .byte 58 # DW_AT_decl_file
+ .byte 11 # DW_FORM_data1
+ .byte 59 # DW_AT_decl_line
+ .byte 11 # DW_FORM_data1
+ .byte 73 # DW_AT_type
+ .byte 19 # DW_FORM_ref4
+ .byte 63 # DW_AT_external
+ .byte 25 # DW_FORM_flag_present
+ .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 37 # DW_FORM_strx1
+ .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
+.Lcu_begin0:
+ .long 75 # Length of Unit
+ .short 5 # DWARF version number
+ .byte 1 # DWARF Unit Type
+ .byte 8 # Address Size (in bytes)
+ .long .debug_abbrev # Offset Into Abbrev. Section
+
+ .byte 1 # Abbrev [1] 0xc:0x43 DW_TAG_compile_unit
+ .byte 0 # DW_AT_producer
+ .short 4 # DW_AT_language
+ .byte 1 # DW_AT_name
+ .long .Lstr_offsets_base0 # DW_AT_str_offsets_base
+ .long 0 # DW_AT_stmt_list
+ .byte 2 # DW_AT_comp_dir
+ .long .Laddr_table_base0 # DW_AT_addr_base
+ .quad 0 # DW_AT_low_pc
+ .byte 0 # DW_AT_ranges
+ .long .Lrnglists_table_base0 # DW_AT_rnglists_base
+
+ .byte 2 # Abbrev [2] 0x2b:0x10 DW_TAG_subprogram
+ .byte 0 # DW_AT_low_pc
+ .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 3 # DW_AT_linkage_name
+ .byte 4 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 1 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ # DW_AT_external
+
+ .byte 3 # Abbrev [3] 0x3b:0xf DW_TAG_subprogram
+ .byte 1 # DW_AT_low_pc
+ .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc
+ .byte 1 # DW_AT_frame_base
+ .byte 86
+ .byte 6 # DW_AT_name
+ .byte 1 # DW_AT_decl_file
+ .byte 5 # DW_AT_decl_line
+ .long 74 # DW_AT_type
+ # DW_AT_external
+
+ .byte 4 # Abbrev [4] 0x4a:0x4 DW_TAG_base_type
+ .byte 5 # DW_AT_name
+ .byte 5 # DW_AT_encoding
+ .byte 4 # DW_AT_byte_size
+ .byte 0 # End Of Children Mark
+
+.section .debug_rnglists,"",@progbits
+.long .Ldebug_rnglist_table_end0-.Ldebug_rnglist_table_start0 # Length
+.Ldebug_rnglist_table_start0:
+ .short 5 # Version
+ .byte 8 # Address size
+ .byte 0 # Segment selector size
+ .long 1 # Offset entry count
+.Lrnglists_table_base0:
+ .long .Ldebug_ranges0-.Lrnglists_table_base0
+.Ldebug_ranges0:
+ .byte 3 # DW_RLE_startx_length
+ .byte 0 # start index
+ .uleb128 .Lfunc_end0-.Lfunc_begin0 # length
+ .byte 3 # DW_RLE_startx_length
+ .byte 1 # start index
+ .uleb128 .Lfunc_end1-.Lfunc_begin1 # length
+ .byte 0 # DW_RLE_end_of_list
+.Ldebug_rnglist_table_end0:
+
+.section .debug_addr,"",@progbits
+ .long 20
+ .short 5
+ .byte 8
+ .byte 0
+.Laddr_table_base0:
+ .quad .Lfunc_begin0
+ .quad .Lfunc_begin1
diff --git a/test/ELF/gdb-index.s b/test/ELF/gdb-index.s
index e7f96066bd02..c9a02fd04d73 100644
--- a/test/ELF/gdb-index.s
+++ b/test/ELF/gdb-index.s
@@ -25,7 +25,7 @@
# DISASM-CHECK: 201004: 90 nop
# DISASM-CHECK: 201005: 90 nop
-# DWARF: .gnu_index contents:
+# DWARF: .gdb_index contents:
# DWARF-NEXT: Version = 7
# DWARF: CU list offset = 0x18, has 2 entries:
# DWARF-NEXT: 0: Offset = 0x0, Length = 0x34
diff --git a/test/ELF/global-offset-table-position-redef-err.s b/test/ELF/global-offset-table-position-redef-err.s
new file mode 100644
index 000000000000..fb2e506c1af6
--- /dev/null
+++ b/test/ELF/global-offset-table-position-redef-err.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 -shared %t.o -o %t.so 2>&1 | FileCheck %s
+
+# On some targets the location of the _GLOBAL_OFFSET_TABLE_ symbol table can
+# matter for the correctness of some relocations. Follow the example of ld.gold
+# and give a multiple definition error if input objects attempt to redefine it.
+
+# CHECK: ld.lld: error: {{.*o}} cannot redefine linker defined symbol '_GLOBAL_OFFSET_TABLE_'
+
+.data
+.global _GLOBAL_OFFSET_TABLE_
+_GLOBAL_OFFSET_TABLE_:
+.word 0
diff --git a/test/ELF/gnu-hash-table-copy.s b/test/ELF/gnu-hash-table-copy.s
index 9d91163258ea..cdd96e3dfd6a 100644
--- a/test/ELF/gnu-hash-table-copy.s
+++ b/test/ELF/gnu-hash-table-copy.s
@@ -13,10 +13,10 @@
# CHECK: Symbol table '.dynsym' contains 4 entries:
# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
-# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND @
-# CHECK-NEXT: 1: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND foo@
-# CHECK-DAG: : {{.*}} 4 OBJECT GLOBAL DEFAULT {{.*}} bar@
-# CHECK-DAG: : {{.*}} 0 FUNC GLOBAL DEFAULT UND zed@
+# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# CHECK-NEXT: 1: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND foo
+# CHECK-DAG: : {{.*}} 4 OBJECT GLOBAL DEFAULT {{.*}} bar
+# CHECK-DAG: : {{.*}} 0 FUNC GLOBAL DEFAULT UND zed
# CHECK: First Hashed Symbol Index: 2
diff --git a/test/ELF/gnu-hash-table-rwsegment.s b/test/ELF/gnu-hash-table-rwsegment.s
index b1a50fbde3a1..ab1b252bc5d4 100644
--- a/test/ELF/gnu-hash-table-rwsegment.s
+++ b/test/ELF/gnu-hash-table-rwsegment.s
@@ -8,8 +8,8 @@
# CHECK-NEXT: Num Buckets: 1
# CHECK-NEXT: First Hashed Symbol Index: 1
# CHECK-NEXT: Num Mask Words: 1
-# CHECK-NEXT: Shift Count: 6
-# CHECK-NEXT: Bloom Filter: [0x400000000004204]
+# CHECK-NEXT: Shift Count: 26
+# CHECK-NEXT: Bloom Filter: [0x400000000000204]
# CHECK-NEXT: Buckets: [1]
# CHECK-NEXT: Values: [0xB8860BA, 0xB887389]
# CHECK-NEXT: }
diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s
index ffbf19fb5c6f..052a5bb20fbf 100644
--- a/test/ELF/gnu-hash-table.s
+++ b/test/ELF/gnu-hash-table.s
@@ -13,7 +13,7 @@
# 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: rm -f %t2-i386.a %t2-x86_64.a %t2-ppc64.a %t2-ppc64le.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
@@ -49,7 +49,7 @@
# EMPTY: DynamicSymbols [
# EMPTY: Symbol {
-# EMPTY: Name: foo@
+# EMPTY: Name: foo
# EMPTY-NEXT: Value: 0x0
# EMPTY-NEXT: Size: 0
# EMPTY-NEXT: Binding: Global
@@ -62,7 +62,7 @@
# EMPTY-NEXT: Num Buckets: 1
# EMPTY-NEXT: First Hashed Symbol Index: 2
# EMPTY-NEXT: Num Mask Words: 1
-# EMPTY-NEXT: Shift Count: 6
+# EMPTY-NEXT: Shift Count: 26
# EMPTY-NEXT: Bloom Filter: [0x0]
# EMPTY-NEXT: Buckets: [0]
# EMPTY-NEXT: Values: []
@@ -87,32 +87,32 @@
# I386: ]
# I386: DynamicSymbols [
# I386: Symbol {
-# I386: Name: @
+# I386: Name:
# I386: Binding: Local
# I386: Section: Undefined
# I386: }
# I386: Symbol {
-# I386: Name: baz@
+# I386: Name: baz
# I386: Binding: Global
# I386: Section: Undefined
# I386: }
# I386: Symbol {
-# I386: Name: xyz@
+# I386: Name: xyz
# I386: Binding: Global
# I386: Section: Undefined
# I386: }
# I386: Symbol {
-# I386: Name: zed@
+# I386: Name: zed
# I386: Binding: Weak
# I386: Section: Undefined
# I386: }
# I386: Symbol {
-# I386: Name: bar@
+# I386: Name: bar
# I386: Binding: Global
# I386: Section: .text
# I386: }
# I386: Symbol {
-# I386: Name: foo@
+# I386: Name: foo
# I386: Binding: Global
# I386: Section: .text
# I386: }
@@ -121,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: 6
-# I386-NEXT: Bloom Filter: [0x4004204]
+# I386-NEXT: Shift Count: 26
+# I386-NEXT: Bloom Filter: [0x4000204]
# I386-NEXT: Buckets: [4]
# I386-NEXT: Values: [0xB8860BA, 0xB887389]
# I386-NEXT: }
@@ -147,32 +147,32 @@
# X86_64: ]
# X86_64: DynamicSymbols [
# X86_64: Symbol {
-# X86_64: Name: @
+# X86_64: Name:
# X86_64: Binding: Local
# X86_64: Section: Undefined
# X86_64: }
# X86_64: Symbol {
-# X86_64: Name: baz@
+# X86_64: Name: baz
# X86_64: Binding: Global
# X86_64: Section: Undefined
# X86_64: }
# X86_64: Symbol {
-# X86_64: Name: xyz@
+# X86_64: Name: xyz
# X86_64: Binding: Global
# X86_64: Section: Undefined
# X86_64: }
# X86_64: Symbol {
-# X86_64: Name: zed@
+# X86_64: Name: zed
# X86_64: Binding: Weak
# X86_64: Section: Undefined
# X86_64: }
# X86_64: Symbol {
-# X86_64: Name: bar@
+# X86_64: Name: bar
# X86_64: Binding: Global
# X86_64: Section: .text
# X86_64: }
# X86_64: Symbol {
-# X86_64: Name: foo@
+# X86_64: Name: foo
# X86_64: Binding: Global
# X86_64: Section: .text
# X86_64: }
@@ -181,8 +181,8 @@
# X86_64-NEXT: Num Buckets: 1
# X86_64-NEXT: First Hashed Symbol Index: 4
# X86_64-NEXT: Num Mask Words: 1
-# X86_64-NEXT: Shift Count: 6
-# X86_64-NEXT: Bloom Filter: [0x400000000004204]
+# X86_64-NEXT: Shift Count: 26
+# X86_64-NEXT: Bloom Filter: [0x400000000000204]
# X86_64-NEXT: Buckets: [4]
# X86_64-NEXT: Values: [0xB8860BA, 0xB887389]
# X86_64-NEXT: }
@@ -207,32 +207,32 @@
# PPC64: ]
# PPC64: DynamicSymbols [
# PPC64: Symbol {
-# PPC64: Name: @
+# PPC64: Name:
# PPC64: Binding: Local
# PPC64: Section: Undefined
# PPC64: }
# PPC64: Symbol {
-# PPC64: Name: baz@
+# PPC64: Name: baz
# PPC64: Binding: Global
# PPC64: Section: Undefined
# PPC64: }
# PPC64: Symbol {
-# PPC64: Name: xyz@
+# PPC64: Name: xyz
# PPC64: Binding: Global
# PPC64: Section: Undefined
# PPC64: }
# PPC64: Symbol {
-# PPC64: Name: zed@
+# PPC64: Name: zed
# PPC64: Binding: Weak
# PPC64: Section: Undefined
# PPC64: }
# PPC64: Symbol {
-# PPC64: Name: bar@
+# PPC64: Name: bar
# PPC64: Binding: Global
# PPC64: Section: .text
# PPC64: }
# PPC64: Symbol {
-# PPC64: Name: foo@
+# PPC64: Name: foo
# PPC64: Binding: Global
# PPC64: Section: .text
# PPC64: }
@@ -241,8 +241,8 @@
# PPC64-NEXT: Num Buckets: 1
# PPC64-NEXT: First Hashed Symbol Index: 4
# PPC64-NEXT: Num Mask Words: 1
-# PPC64-NEXT: Shift Count: 6
-# PPC64-NEXT: Bloom Filter: [0x400000000004204]
+# PPC64-NEXT: Shift Count: 26
+# PPC64-NEXT: Bloom Filter: [0x400000000000204]
# PPC64-NEXT: Buckets: [4]
# PPC64-NEXT: Values: [0xB8860BA, 0xB887389]
# PPC64-NEXT: }
diff --git a/test/ELF/gnu-ifunc-empty.s b/test/ELF/gnu-ifunc-empty.s
new file mode 100644
index 000000000000..90798532f973
--- /dev/null
+++ b/test/ELF/gnu-ifunc-empty.s
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+
+// Verifies that .rela_iplt_{start,end} point to a dummy section
+// if .rela.iplt does not exist.
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -static %t.o -o %t.exe
+// RUN: llvm-objdump -syms %t.exe | FileCheck %s
+
+// CHECK: 0000000000200000 .text 00000000 .hidden __rela_iplt_end
+// CHECK: 0000000000200000 .text 00000000 .hidden __rela_iplt_start
+
+.globl _start
+_start:
+ movl $__rela_iplt_start, %edx
+ movl $__rela_iplt_end, %edx
diff --git a/test/ELF/gnu-ifunc-i386.s b/test/ELF/gnu-ifunc-i386.s
index f379bf1b28e8..bfc1587f0114 100644
--- a/test/ELF/gnu-ifunc-i386.s
+++ b/test/ELF/gnu-ifunc-i386.s
@@ -16,14 +16,14 @@
// CHECK-NEXT: Offset: 0xD4
// CHECK-NEXT: Size: 16
// CHECK-NEXT: Link: 0
-// CHECK-NEXT: Info: 0
+// CHECK-NEXT: Info: 4
// CHECK-NEXT: AddressAlignment: 4
// CHECK-NEXT: EntrySize: 8
// CHECK-NEXT: }
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rel.plt {
-// CHECK-NEXT: 0x12000 R_386_IRELATIVE
-// CHECK-NEXT: 0x12004 R_386_IRELATIVE
+// CHECK-NEXT: 0x402000 R_386_IRELATIVE
+// CHECK-NEXT: 0x402004 R_386_IRELATIVE
// CHECK-NEXT: }
// CHECK-NEXT: ]
@@ -39,7 +39,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: __rel_iplt_end
-// CHECK-NEXT: Value: 0x100E4
+// CHECK-NEXT: Value: 0x4000E4
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
@@ -61,7 +61,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: _start
-// CHECK-NEXT: Value: 0x11002
+// CHECK-NEXT: Value: 0x401002
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: None
@@ -70,7 +70,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: bar
-// CHECK-NEXT: Value: 0x11001
+// CHECK-NEXT: Value: 0x401001
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: GNU_IFunc
@@ -79,7 +79,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: foo
-// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Value: 0x401000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: GNU_IFunc
@@ -90,22 +90,22 @@
// DISASM: Disassembly of section .text:
// DISASM-NEXT: foo:
-// DISASM-NEXT: 11000: c3 retl
+// DISASM-NEXT: 401000: c3 retl
// DISASM: bar:
-// DISASM-NEXT: 11001: c3 retl
+// DISASM-NEXT: 401001: c3 retl
// DISASM: _start:
-// DISASM-NEXT: 11002: e8 19 00 00 00 calll 25
-// DISASM-NEXT: 11007: e8 24 00 00 00 calll 36
-// DISASM-NEXT: 1100c: ba d4 00 01 00 movl $65748, %edx
-// DISASM-NEXT: 11011: ba e4 00 01 00 movl $65764, %edx
+// DISASM-NEXT: 401002: e8 19 00 00 00 calll 25
+// DISASM-NEXT: 401007: e8 24 00 00 00 calll 36
+// DISASM-NEXT: 40100c: ba d4 00 40 00 movl $4194516, %edx
+// DISASM-NEXT: 401011: ba e4 00 40 00 movl $4194532, %edx
// DISASM-NEXT: Disassembly of section .plt:
// DISASM-NEXT: .plt:
-// DISASM-NEXT: 11020: ff 25 00 20 01 00 jmpl *73728
-// DISASM-NEXT: 11026: 68 10 00 00 00 pushl $16
-// DISASM-NEXT: 1102b: e9 e0 ff ff ff jmp -32 <_start+0xe>
-// DISASM-NEXT: 11030: ff 25 04 20 01 00 jmpl *73732
-// DISASM-NEXT: 11036: 68 18 00 00 00 pushl $24
-// DISASM-NEXT: 1103b: e9 d0 ff ff ff jmp -48 <_start+0xe>
+// DISASM-NEXT: 401020: ff 25 00 20 40 00 jmpl *4202496
+// DISASM-NEXT: 401026: 68 10 00 00 00 pushl $16
+// DISASM-NEXT: 40102b: e9 e0 ff ff ff jmp -32 <_start+0xe>
+// DISASM-NEXT: 401030: ff 25 04 20 40 00 jmpl *4202500
+// DISASM-NEXT: 401036: 68 18 00 00 00 pushl $24
+// DISASM-NEXT: 40103b: e9 d0 ff ff ff jmp -48 <_start+0xe>
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/gnu-ifunc-plt-i386.s b/test/ELF/gnu-ifunc-plt-i386.s
index 14369bf6388b..3ed4e7616f57 100644
--- a/test/ELF/gnu-ifunc-plt-i386.s
+++ b/test/ELF/gnu-ifunc-plt-i386.s
@@ -10,16 +10,16 @@
// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
// CHECK: Relocations [
// CHECK-NEXT: Section (4) .rel.plt {
-// CHECK-NEXT: 0x1200C R_386_JUMP_SLOT bar2
-// CHECK-NEXT: 0x12010 R_386_JUMP_SLOT zed2
-// CHECK-NEXT: 0x12014 R_386_IRELATIVE
-// CHECK-NEXT: 0x12018 R_386_IRELATIVE
+// CHECK-NEXT: 0x40200C R_386_JUMP_SLOT bar2
+// CHECK-NEXT: 0x402010 R_386_JUMP_SLOT zed2
+// CHECK-NEXT: 0x402014 R_386_IRELATIVE
+// CHECK-NEXT: 0x402018 R_386_IRELATIVE
// Check that IRELATIVE .got.plt entries point to ifunc resolver and not
// back to the plt entry + 6.
// GOTPLT: Contents of section .got.plt:
-// GOTPLT: 12000 00300100 00000000 00000000 36100100
-// GOTPLT-NEXT: 12010 46100100 00100100 01100100
+// GOTPLT: 402000 00304000 00000000 00000000 36104000
+// GOTPLT-NEXT: 402010 46104000 00104000 01104000
// Check that the PLTRELSZ tag includes the IRELATIVE relocations
// CHECK: DynamicSection [
@@ -28,34 +28,38 @@
// Check that a PLT header is written and the ifunc entries appear last
// DISASM: Disassembly of section .text:
// DISASM-NEXT: foo:
-// DISASM-NEXT: 11000: c3 retl
+// DISASM-NEXT: 401000: c3 retl
// DISASM: bar:
-// DISASM-NEXT: 11001: c3 retl
+// DISASM-NEXT: 401001: c3 retl
// DISASM: _start:
-// DISASM-NEXT: 11002: e8 49 00 00 00 calll 73
-// DISASM-NEXT: 11007: e8 54 00 00 00 calll 84
-// DISASM-NEXT: 1100c: e8 1f 00 00 00 calll 31
-// DISASM-NEXT: 11011: e8 2a 00 00 00 calll 42
+// DISASM-NEXT: 401002: e8 49 00 00 00 calll 73
+// DISASM-NEXT: 401007: e8 54 00 00 00 calll 84
+// DISASM-NEXT: 40100c: e8 1f 00 00 00 calll 31
+// DISASM-NEXT: 401011: e8 2a 00 00 00 calll 42
// DISASM-NEXT: Disassembly of section .plt:
// DISASM-NEXT: .plt:
-// DISASM-NEXT: 11020: ff 35 04 20 01 00 pushl 73732
-// DISASM-NEXT: 11026: ff 25 08 20 01 00 jmpl *73736
-// DISASM-NEXT: 1102c: 90 nop
-// DISASM-NEXT: 1102d: 90 nop
-// DISASM-NEXT: 1102e: 90 nop
-// DISASM-NEXT: 1102f: 90 nop
-// DISASM-NEXT: 11030: ff 25 0c 20 01 00 jmpl *73740
-// DISASM-NEXT: 11036: 68 00 00 00 00 pushl $0
-// DISASM-NEXT: 1103b: e9 e0 ff ff ff jmp -32 <.plt>
-// DISASM-NEXT: 11040: ff 25 10 20 01 00 jmpl *73744
-// DISASM-NEXT: 11046: 68 08 00 00 00 pushl $8
-// DISASM-NEXT: 1104b: e9 d0 ff ff ff jmp -48 <.plt>
-// DISASM-NEXT: 11050: ff 25 14 20 01 00 jmpl *73748
-// DISASM-NEXT: 11056: 68 30 00 00 00 pushl $48
-// DISASM-NEXT: 1105b: e9 e0 ff ff ff jmp -32 <.plt+0x20>
-// DISASM-NEXT: 11060: ff 25 18 20 01 00 jmpl *73752
-// DISASM-NEXT: 11066: 68 38 00 00 00 pushl $56
-// DISASM-NEXT: 1106b: e9 d0 ff ff ff jmp -48 <.plt+0x20>
+// DISASM-NEXT: 401020: ff 35 04 20 40 00 pushl 4202500
+// DISASM-NEXT: 401026: ff 25 08 20 40 00 jmpl *4202504
+// DISASM-NEXT: 40102c: 90 nop
+// DISASM-NEXT: 40102d: 90 nop
+// DISASM-NEXT: 40102e: 90 nop
+// DISASM-NEXT: 40102f: 90 nop
+// DISASM-EMPTY:
+// DISASM-NEXT: bar2@plt:
+// DISASM-NEXT: 401030: ff 25 0c 20 40 00 jmpl *4202508
+// DISASM-NEXT: 401036: 68 00 00 00 00 pushl $0
+// DISASM-NEXT: 40103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: zed2@plt:
+// DISASM-NEXT: 401040: ff 25 10 20 40 00 jmpl *4202512
+// DISASM-NEXT: 401046: 68 08 00 00 00 pushl $8
+// DISASM-NEXT: 40104b: e9 d0 ff ff ff jmp -48 <.plt>
+// DISASM-NEXT: 401050: ff 25 14 20 40 00 jmpl *4202516
+// DISASM-NEXT: 401056: 68 30 00 00 00 pushl $48
+// DISASM-NEXT: 40105b: e9 e0 ff ff ff jmp -32 <zed2@plt>
+// DISASM-NEXT: 401060: ff 25 18 20 40 00 jmpl *4202520
+// DISASM-NEXT: 401066: 68 38 00 00 00 pushl $56
+// DISASM-NEXT: 40106b: e9 d0 ff ff ff jmp -48 <zed2@plt>
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/gnu-ifunc-plt.s b/test/ELF/gnu-ifunc-plt.s
index b88f32cb7306..aa1c3c72f593 100644
--- a/test/ELF/gnu-ifunc-plt.s
+++ b/test/ELF/gnu-ifunc-plt.s
@@ -42,18 +42,22 @@
// DISASM-NEXT: 201020: ff 35 e2 0f 00 00 pushq 4066(%rip)
// DISASM-NEXT: 201026: ff 25 e4 0f 00 00 jmpq *4068(%rip)
// DISASM-NEXT: 20102c: 0f 1f 40 00 nopl (%rax)
+// DISASM-EMPTY:
+// DISASM-NEXT: bar2@plt:
// DISASM-NEXT: 201030: ff 25 e2 0f 00 00 jmpq *4066(%rip)
// DISASM-NEXT: 201036: 68 00 00 00 00 pushq $0
// DISASM-NEXT: 20103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: zed2@plt:
// DISASM-NEXT: 201040: ff 25 da 0f 00 00 jmpq *4058(%rip)
// DISASM-NEXT: 201046: 68 01 00 00 00 pushq $1
// DISASM-NEXT: 20104b: e9 d0 ff ff ff jmp -48 <.plt>
// DISASM-NEXT: 201050: ff 25 d2 0f 00 00 jmpq *4050(%rip)
// DISASM-NEXT: 201056: 68 00 00 00 00 pushq $0
-// DISASM-NEXT: 20105b: e9 e0 ff ff ff jmp -32 <.plt+0x20>
+// DISASM-NEXT: 20105b: e9 e0 ff ff ff jmp -32 <zed2@plt>
// DISASM-NEXT: 201060: ff 25 ca 0f 00 00 jmpq *4042(%rip)
// DISASM-NEXT: 201066: 68 01 00 00 00 pushq $1
-// DISASM-NEXT: 20106b: e9 d0 ff ff ff jmp -48 <.plt+0x20>
+// DISASM-NEXT: 20106b: e9 d0 ff ff ff jmp -48 <zed2@plt>
.text
.type foo STT_GNU_IFUNC
diff --git a/test/ELF/gnu-ifunc-relative.s b/test/ELF/gnu-ifunc-relative.s
index d797301d03ad..65750ec46f61 100644
--- a/test/ELF/gnu-ifunc-relative.s
+++ b/test/ELF/gnu-ifunc-relative.s
@@ -1,7 +1,9 @@
// 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
+// RUN: ld.lld --strip-all %t.o -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+// RUN: ld.lld %t.o -o %t
+// RUN: llvm-readobj -r -t %t | FileCheck %s --check-prefixes=CHECK,SYM
.type foo STT_GNU_IFUNC
.globl foo
@@ -16,8 +18,8 @@ _start:
// CHECK-NEXT: R_X86_64_IRELATIVE - 0x[[ADDR:.*]]
// CHECK-NEXT: }
-// CHECK: Name: foo
-// CHECK-NEXT: Value: 0x[[ADDR]]
-// CHECK-NEXT: Size: 0
-// CHECK-NEXT: Binding: Global
-// CHECK-NEXT: Type: GNU_IFunc
+// SYM: Name: foo
+// SYM-NEXT: Value: 0x[[ADDR]]
+// SYM-NEXT: Size: 0
+// SYM-NEXT: Binding: Global
+// SYM-NEXT: Type: GNU_IFunc
diff --git a/test/ELF/gnu-ifunc-shared.s b/test/ELF/gnu-ifunc-shared.s
index bde6807e4b43..bc91ff9e5b32 100644
--- a/test/ELF/gnu-ifunc-shared.s
+++ b/test/ELF/gnu-ifunc-shared.s
@@ -23,15 +23,19 @@
// DISASM-NEXT: 1020: ff 35 e2 0f 00 00 pushq 4066(%rip)
// DISASM-NEXT: 1026: ff 25 e4 0f 00 00 jmpq *4068(%rip)
// DISASM-NEXT: 102c: 0f 1f 40 00 nopl (%rax)
+// DISASM-EMPTY:
+// DISASM-NEXT: fct2@plt:
// DISASM-NEXT: 1030: ff 25 e2 0f 00 00 jmpq *4066(%rip)
// DISASM-NEXT: 1036: 68 00 00 00 00 pushq $0
// DISASM-NEXT: 103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: f2@plt:
// DISASM-NEXT: 1040: ff 25 da 0f 00 00 jmpq *4058(%rip)
// DISASM-NEXT: 1046: 68 01 00 00 00 pushq $1
// DISASM-NEXT: 104b: e9 d0 ff ff ff jmp -48 <.plt>
// DISASM-NEXT: 1050: ff 25 d2 0f 00 00 jmpq *4050(%rip)
// DISASM-NEXT: 1056: 68 00 00 00 00 pushq $0
-// DISASM-NEXT: 105b: e9 e0 ff ff ff jmp -32 <.plt+0x20>
+// DISASM-NEXT: 105b: e9 e0 ff ff ff jmp -32 <f2@plt>
// CHECK: Relocations [
// CHECK-NEXT: Section (4) .rela.plt {
diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s
index faf51b4b6216..25c71b033e20 100644
--- a/test/ELF/gnu-ifunc.s
+++ b/test/ELF/gnu-ifunc.s
@@ -16,10 +16,12 @@
// CHECK-NEXT: Offset: 0x158
// CHECK-NEXT: Size: 48
// CHECK-NEXT: Link: 0
-// CHECK-NEXT: Info: 0
+// CHECK-NEXT: Info: [[GOTPLT:.*]]
// CHECK-NEXT: AddressAlignment: 8
// CHECK-NEXT: EntrySize: 24
// CHECK-NEXT: }
+// CHECK: Index: [[GOTPLT]]
+// CHECK-NEXT: Name: .got.plt
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rela.plt {
// CHECK-NEXT: 0x202000 R_X86_64_IRELATIVE
diff --git a/test/ELF/gnu-unique.s b/test/ELF/gnu-unique.s
index 06f370434cd8..83f0f233f4f3 100644
--- a/test/ELF/gnu-unique.s
+++ b/test/ELF/gnu-unique.s
@@ -20,7 +20,7 @@ _start:
.type symb, @gnu_unique_object
symb:
-# GNU: Name: symb@
+# GNU: Name: symb
# GNU-NEXT: Value:
# GNU-NEXT: Size: 0
# GNU-NEXT: Binding: Unique
@@ -29,7 +29,7 @@ symb:
# GNU-NEXT: Section: .data
# GNU-NEXT: }
-# NO: Name: symb@
+# NO: Name: symb
# NO-NEXT: Value:
# NO-NEXT: Size: 0
# NO-NEXT: Binding: Global
diff --git a/test/ELF/got-i386.s b/test/ELF/got-i386.s
index 7fb87e0dadbd..3b2ef1a31c2c 100644
--- a/test/ELF/got-i386.s
+++ b/test/ELF/got-i386.s
@@ -10,7 +10,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Address: 0x402000
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Link:
@@ -19,7 +19,7 @@
// CHECK: Symbol {
// CHECK: Name: bar
-// CHECK-NEXT: Value: 0x12000
+// CHECK-NEXT: Value: 0x402000
// CHECK-NEXT: Size: 10
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Object
@@ -28,7 +28,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: obj
-// CHECK-NEXT: Value: 0x1200A
+// CHECK-NEXT: Value: 0x40200A
// CHECK-NEXT: Size: 10
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Object
@@ -36,14 +36,14 @@
// CHECK-NEXT: Section: .bss
// CHECK-NEXT: }
-// 0x12000 - 0 = addr(.got) = 0x12000
-// 0x1200A - 10 = addr(.got) = 0x12000
-// 0x1200A + 5 - 15 = addr(.got) = 0x12000
+// 0x402000 - 0 = addr(.got) = 0x402000
+// 0x40200A - 10 = addr(.got) = 0x402000
+// 0x40200A + 5 - 15 = addr(.got) = 0x402000
// DISASM: Disassembly of section .text:
// DISASM-NEXT: _start:
-// DISASM-NEXT: 11000: c7 81 00 00 00 00 01 00 00 00 movl $1, (%ecx)
-// DISASM-NEXT: 1100a: c7 81 0a 00 00 00 02 00 00 00 movl $2, 10(%ecx)
-// DISASM-NEXT: 11014: c7 81 0f 00 00 00 03 00 00 00 movl $3, 15(%ecx)
+// DISASM-NEXT: 401000: c7 81 00 00 00 00 01 00 00 00 movl $1, (%ecx)
+// DISASM-NEXT: 40100a: c7 81 0a 00 00 00 02 00 00 00 movl $2, 10(%ecx)
+// DISASM-NEXT: 401014: c7 81 0f 00 00 00 03 00 00 00 movl $3, 15(%ecx)
.global _start
_start:
diff --git a/test/ELF/got32-i386-pie-rw.s b/test/ELF/got32-i386-pie-rw.s
index 45d2ec154675..180ba864fbfd 100644
--- a/test/ELF/got32-i386-pie-rw.s
+++ b/test/ELF/got32-i386-pie-rw.s
@@ -1,7 +1,7 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
# RUN: ld.lld %t.o -o %t -pie
-# RUN: llvm-readelf -r -s %t | FileCheck %s
+# RUN: llvm-readelf -r -S %t | FileCheck %s
# Unlike bfd and gold we accept this.
diff --git a/test/ELF/got32-i386.s b/test/ELF/got32-i386.s
index dce50d0afc2e..ff67a4bbe0ef 100644
--- a/test/ELF/got32-i386.s
+++ b/test/ELF/got32-i386.s
@@ -14,10 +14,10 @@ _start:
## 73728 == 0x12000 == ADDR(.got)
# CHECK: _start:
-# CHECK-NEXT: 11001: 8b 1d {{.*}} movl 73728, %ebx
+# CHECK-NEXT: 401001: 8b 1d {{.*}} movl 4202496, %ebx
# CHECK: Sections:
# CHECK: Name Size Address
-# CHECK: .got 00000004 0000000000012000
+# CHECK: .got 00000004 0000000000402000
# 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 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 610051e8a962..88e7e31ee561 100644
--- a/test/ELF/got32x-i386.s
+++ b/test/ELF/got32x-i386.s
@@ -33,13 +33,13 @@
## 73728 == 0x12000 == ADDR(.got)
# CHECK: _start:
-# 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-NEXT: 401001: 8b 05 {{.*}} movl 4206592, %eax
+# CHECK-NEXT: 401007: 8b 1d {{.*}} movl 4206592, %ebx
+# CHECK-NEXT: 40100d: 8b 80 {{.*}} movl -4(%eax), %eax
+# CHECK-NEXT: 401013: 8b 83 {{.*}} movl -4(%ebx), %eax
# CHECK: Sections:
# CHECK: Name Size Address
-# CHECK: .got 00000004 0000000000013000
+# CHECK: .got 00000004 0000000000403000
# RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \
# RUN: FileCheck %s --check-prefix=ERR
diff --git a/test/ELF/hexagon-eflag.s b/test/ELF/hexagon-eflag.s
new file mode 100644
index 000000000000..01cb5e5b0f29
--- /dev/null
+++ b/test/ELF/hexagon-eflag.s
@@ -0,0 +1,7 @@
+# REQUIRES: hexagon
+# RUN: llvm-mc -filetype=obj -mv62 -triple=hexagon-unknown-elf %s -o %t
+# RUN: llvm-mc -filetype=obj -mv60 -triple=hexagon-unknown-elf %S/Inputs/hexagon.s -o %t2
+# RUN: ld.lld %t2 %t -o %t3
+# RUN: llvm-readelf -h %t3 | FileCheck %s
+# Verify that the largest arch in the input list is selected.
+# CHECK: Flags: 0x62
diff --git a/test/ELF/hexagon-shared.s b/test/ELF/hexagon-shared.s
new file mode 100644
index 000000000000..97f8e84f9257
--- /dev/null
+++ b/test/ELF/hexagon-shared.s
@@ -0,0 +1,46 @@
+# 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-shared.s -o %t2.o
+# RUN: ld.lld -shared %t2.o -soname %t3.so -o %t3.so
+# RUN: ld.lld -shared %t %t3.so -soname %t4.so -o %t4.so
+# RUN: llvm-objdump -d -j .plt %t4.so | FileCheck --check-prefix=PLT %s
+# RUN: llvm-objdump -d -j .text %t4.so | FileCheck --check-prefix=TEXT %s
+# RUN: llvm-objdump -D -j .got %t4.so | FileCheck --check-prefix=GOT %s
+
+.global foo
+foo:
+
+# _HEX_32_PCREL
+.word _DYNAMIC - .
+call ##bar
+
+# R_HEX_PLT_B22_PCREL
+call bar@PLT
+
+# R_HEX_GOT_11_X and R_HEX_GOT_32_6_X
+r2=add(pc,##_GLOBAL_OFFSET_TABLE_@PCREL)
+r0 = memw (r2+##bar@GOT)
+jumpr r0
+
+# R_HEX_GOT_16_X
+r0 = add(r1,##bar@GOT)
+
+# PLT: { immext(#65472
+# PLT: r28 = add(pc,##65488) }
+# PLT: { r14 -= add(r28,#16)
+# PLT: r15 = memw(r28+#8)
+# PLT: r28 = memw(r28+#4) }
+# PLT: { r14 = asr(r14,#2)
+# PLT: jumpr r28 }
+# PLT: { trap0(#219) }
+# PLT: immext(#65472)
+# PLT: r14 = add(pc,##65472) }
+# PLT: r28 = memw(r14+#0) }
+# PLT: jumpr r28 }
+
+# TEXT: 10000: 00 00 02 00 00020000
+# TEXT: { call 0x10050 }
+# TEXT: r0 = add(r1,##65664) }
+
+# GOT: .got:
+# GOT: 30080: 00 00 00 00 00000000 <unknown>
diff --git a/test/ELF/hexagon.s b/test/ELF/hexagon.s
index 1b3273374c67..c8dd271815e8 100644
--- a/test/ELF/hexagon.s
+++ b/test/ELF/hexagon.s
@@ -4,28 +4,220 @@
# RUN: ld.lld %t2 %t -o %t3
# RUN: llvm-objdump -d %t3 | FileCheck %s
-# Note: 69632 == 0x11000
+# Note: 131072 == 0x20000
# R_HEX_32_6_X
# R_HEX_12_X
if (p0) r0 = ##_start
-# CHECK: immext(#69632)
-# CHECK: if (p0) r0 = ##69632
+# CHECK: immext(#131072)
+# CHECK: if (p0) r0 = ##131072
# R_HEX_B15_PCREL
if (p0) jump:nt #_start
-# CHECK: if (p0) jump:nt 0x11000
+# CHECK: if (p0) jump:nt 0x20000
# R_HEX_B32_PCREL_X
# R_HEX_B15_PCREL_X
if (p0) jump:nt ##_start
-# CHECK: if (p0) jump:nt 0x11000
+# CHECK: if (p0) jump:nt 0x20000
# R_HEX_B22_PCREL
call #_start
-# CHECK: call 0x11000
+# CHECK: call 0x20000
# R_HEX_B32_PCREL_X
# R_HEX_B22_PCREL_X
call ##_start
# CHECK: immext(#4294967232)
-# CHECK: call 0x11000
+# CHECK: call 0x20000
+
+# R_HEX_6_X tests:
+# One test for each mask in the lookup table.
+
+#0x38000000
+if (!P0) memw(r0+#8)=##_start
+# CHECK: 38c0c100 if (!p0) memw(r0+#8) = ##131072 }
+
+#0x39000000
+{ p0 = p1
+ if (!P0.new) memw(r0+#0)=##_start }
+# CHECK: 39c0c000 if (!p0.new) memw(r0+#0) = ##131072 }
+
+#0x3e000000
+memw(r0+##_start)+=r1
+# CHECK: 3e40c001 memw(r0+##131072) += r1 }
+
+#0x3f000000
+memw(r0+##_start)+=#4
+# CHECK: 3f40c004 memw(r0+##131072) += #4 }
+
+#0x40000000
+{ r0 = r1
+ if (p0) memb(r0+##_start)=r0.new }
+# CHECK: 40a0c200 if (p0) memb(r0+##131072) = r0.new }
+
+#0x41000000
+if (p0) r0=memb(r1+##_start)
+# CHECK: 4101c000 if (p0) r0 = memb(r1+##131072) }
+
+#0x42000000
+{ r0 = r1
+ p0 = p1
+ if (p0.new) memb(r0+##_start)=r0.new }
+# CHECK: 42a0c200 if (p0.new) memb(r0+##131072) = r0.new }
+
+#0x43000000
+{ p0 = p1
+ if (P0.new) r0=memb(r0+##_start) }
+# CHECK: 4300c000 if (p0.new) r0 = memb(r0+##131072) }
+
+#0x44000000
+if (!p0) memb(r0+##_start)=r1
+# CHECK: 4400c100 if (!p0) memb(r0+##131072) = r1 }
+
+#0x45000000
+if (!p0) r0=memb(r1+##_start)
+# CHECK: 4501c000 if (!p0) r0 = memb(r1+##131072) }
+
+#0x46000000
+{ p0 = p1
+ if (!p0.new) memb(r0+##_start)=r1 }
+# CHECK: 4600c100 if (!p0.new) memb(r0+##131072) = r1 }
+
+#0x47000000
+{ p0 = p1
+ if (!p0.new) r0=memb(r1+##_start) }
+# CHECK: 4701c000 if (!p0.new) r0 = memb(r1+##131072) }
+
+#0x6a000000 -- Note 4294967132 == -0xa4 the distance between
+# here and _start, so this will change if
+# tests are added between here and _start
+r0=add(pc,##_start@pcrel)
+# CHECK: 6a49ce00 r0 = add(pc,##4294967132) }
+
+#0x7c000000
+r1:0=combine(#8,##_start)
+# CHECK: 7c80c100 r1:0 = combine(#8,##131072) }
+
+#0x9a000000
+r1:0=memb_fifo(r2=##_start)
+# CHECK: 9a82d000 r1:0 = memb_fifo(r2=##131072) }
+
+#0x9b000000
+r0=memb(r1=##_start)
+# CHECK: 9b01d000 r0 = memb(r1=##131072) }
+
+#0x9c000000
+r1:0=memb_fifo(r2<<#2+##_start)
+# CHECK: 9c82f000 r1:0 = memb_fifo(r2<<#2+##131072) }
+
+#0x9d000000
+r0=memb(r1<<#2+##_start)
+# CHECK: 9d01f000 r0 = memb(r1<<#2+##131072) }
+
+#0x9f000000
+if (!p0) r0=memb(##_start)
+# CHECK: 9f00e880 if (!p0) r0 = memb(##131072) }
+
+#0xab000000
+memb(r0=##_start)=r1
+# CHECK: ab00c180 memb(r0=##131072) = r1 }
+
+#0xad000000
+memb(r0<<#2+##_start)=r1
+# CHECK: ad00e180 memb(r0<<#2+##131072) = r1 }
+
+#0xaf000000
+if (!p0) memb(##_start)=r1
+# CHECK: af00c184 if (!p0) memb(##131072) = r1 }
+
+#0xd7000000
+r0=add(##_start,mpyi(r1,r2))
+# CHECK: d701c200 r0 = add(##131072,mpyi(r1,r2)) }
+
+#0xd8000000
+R0=add(##_start,mpyi(r0,#2))
+# CHECK: d800c002 r0 = add(##131072,mpyi(r0,#2)) }
+
+#0xdb000000
+r0=add(r1,add(r2,##_start))
+# CHECK: db01c002 r0 = add(r1,add(r2,##131072)) }
+
+#0xdf000000
+r0=add(r1,mpyi(r2,##_start))
+# CHECK: df82c001 r0 = add(r1,mpyi(r2,##131072)) }
+
+# Duplex form of R_HEX_6_X
+# R_HEX_32_6_X
+# R_HEX_6_X
+{ r0 = ##_start; r2 = r16 }
+# CHECK: 28003082 r0 = ##131072; r2 = r16 }
+
+# R_HEX_HI16
+r0.h = #HI(_start)
+# CHECK: r0.h = #2
+
+# R_HEX_LO16
+r0.l = #LO(_start)
+# CHECK: r0.l = #0
+
+# R_HEX_8_X has 3 relocation mask variations
+#0xde000000
+r0=sub(##_start, asl(r0, #1))
+# CHECK: de00c106 r0 = sub(##131072,asl(r0,#1)) }
+
+#0x3c000000
+memw(r0+#0) = ##_start
+# CHECK: 3c40c000 memw(r0+#0) = ##131072 }
+
+# The rest:
+r1:0=combine(r2,##_start);
+# CHECK: 7302e000 r1:0 = combine(r2,##131072) }
+
+# R_HEX_32:
+r_hex_32:
+.word _start
+# CHECK: 00020000
+
+# R_HEX_16_X has 4 relocation mask variations
+# 0x48000000
+memw(##_start) = r0
+# CHECK: 4880c000 memw(##131072) = r0 }
+
+# 0x49000000
+r0 = memw(##_start)
+# CHECK: 4980c000 r0 = memw(##131072)
+
+# 0x78000000
+r0 = ##_start
+# CHECK: 7800c000 r0 = ##131072 }
+
+# 0xb0000000
+r0 = add(r1, ##_start)
+# CHECK: b001c000 r0 = add(r1,##131072) }
+
+# R_HEX_B9_PCREL:
+{r0=#1 ; jump #_start}
+# CHECK: jump 0x20000
+
+# R_HEX_B9_PCREL_X:
+{r0=#1 ; jump ##_start}
+# CHECK: jump 0x20000
+
+# R_HEX_B13_PCREL
+if (r0 == #0) jump:t #_start
+# CHECK: if (r0==#0) jump:t 0x20000
+
+# R_HEX_9_X
+p0 = !cmp.gtu(r0, ##_start)
+# CHECK: p0 = !cmp.gtu(r0,##131072)
+
+# R_HEX_10_X
+p0 = !cmp.gt(r0, ##_start)
+# CHECK: p0 = !cmp.gt(r0,##131072)
+
+# R_HEX_11_X
+r0 = memw(r1+##_start)
+# CHECK: r0 = memw(r1+##131072)
+
+memw(r0+##_start) = r1
+# CHECK: memw(r0+##131072) = r1
diff --git a/test/ELF/i386-linkonce.s b/test/ELF/i386-linkonce.s
new file mode 100644
index 000000000000..c06b042c7638
--- /dev/null
+++ b/test/ELF/i386-linkonce.s
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i386-linux-gnu %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=i386-linux-gnu %p/Inputs/i386-linkonce.s -o %t2.o
+// RUN: llvm-ar rcs %t2.a %t2.o
+// RUN: ld.lld %t.o %t2.a -o %t
+
+ .globl _start
+_start:
+ call _strchr1
diff --git a/test/ELF/i386-pc8-pc16-addend.s b/test/ELF/i386-pc8-pc16-addend.s
index fc648b035509..8dad18fb2e65 100644
--- a/test/ELF/i386-pc8-pc16-addend.s
+++ b/test/ELF/i386-pc8-pc16-addend.s
@@ -4,11 +4,11 @@
# RUN: ld.lld %t1.o -o %t.out
# RUN: llvm-objdump -s -t %t.out | FileCheck %s
# CHECK: Contents of section .text:
-# CHECK-NEXT: 11000 020000
-## 0x11003 - 0x11000 + addend(-1) = 0x02
-## 0x11003 - 0x11001 + addend(-2) = 0x0000
+# CHECK-NEXT: 401000 020000
+## 0x401003 - 0x401000 + addend(-1) = 0x02
+## 0x401003 - 0x401001 + addend(-2) = 0x0000
# CHECK: SYMBOL TABLE:
-# CHECK: 00011003 .und
+# CHECK: 00401003 .und
.byte und-.-1
.short und-.-2
diff --git a/test/ELF/i386-retpoline-nopic.s b/test/ELF/i386-retpoline-nopic.s
index 79dd5a63cd69..6d0a699cf306 100644
--- a/test/ELF/i386-retpoline-nopic.s
+++ b/test/ELF/i386-retpoline-nopic.s
@@ -8,56 +8,56 @@
// 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-NEXT: 401010: ff 35 04 20 40 00 pushl 4202500
+// CHECK-NEXT: 401016: 50 pushl %eax
+// CHECK-NEXT: 401017: a1 08 20 40 00 movl 4202504, %eax
+// CHECK-NEXT: 40101c: e8 0f 00 00 00 calll 15 <.plt+0x20>
+// CHECK-NEXT: 401021: f3 90 pause
+// CHECK-NEXT: 401023: 0f ae e8 lfence
+// CHECK-NEXT: 401026: eb f9 jmp -7 <.plt+0x11>
+// CHECK-NEXT: 401028: cc int3
+// CHECK-NEXT: 401029: cc int3
+// CHECK-NEXT: 40102a: cc int3
+// CHECK-NEXT: 40102b: cc int3
+// CHECK-NEXT: 40102c: cc int3
+// CHECK-NEXT: 40102d: cc int3
+// CHECK-NEXT: 40102e: cc int3
+// CHECK-NEXT: 40102f: cc int3
+// CHECK-NEXT: 401030: 89 0c 24 movl %ecx, (%esp)
+// CHECK-NEXT: 401033: 8b 4c 24 04 movl 4(%esp), %ecx
+// CHECK-NEXT: 401037: 89 44 24 04 movl %eax, 4(%esp)
+// CHECK-NEXT: 40103b: 89 c8 movl %ecx, %eax
+// CHECK-NEXT: 40103d: 59 popl %ecx
+// CHECK-NEXT: 40103e: c3 retl
+// CHECK-NEXT: 40103f: cc int3
+// CHECK-NEXT: 401040: 50 pushl %eax
+// CHECK-NEXT: 401041: a1 0c 20 40 00 movl 4202508, %eax
+// CHECK-NEXT: 401046: e8 e5 ff ff ff calll -27 <.plt+0x20>
+// CHECK-NEXT: 40104b: e9 d1 ff ff ff jmp -47 <.plt+0x11>
+// CHECK-NEXT: 401050: 68 00 00 00 00 pushl $0
+// CHECK-NEXT: 401055: e9 b6 ff ff ff jmp -74 <.plt>
+// CHECK-NEXT: 40105a: cc int3
+// CHECK-NEXT: 40105b: cc int3
+// CHECK-NEXT: 40105c: cc int3
+// CHECK-NEXT: 40105d: cc int3
+// CHECK-NEXT: 40105e: cc int3
+// CHECK-NEXT: 40105f: cc int3
+// CHECK-NEXT: 401060: 50 pushl %eax
+// CHECK-NEXT: 401061: a1 10 20 40 00 movl 4202512, %eax
+// CHECK-NEXT: 401066: e8 c5 ff ff ff calll -59 <.plt+0x20>
+// CHECK-NEXT: 40106b: e9 b1 ff ff ff jmp -79 <.plt+0x11>
+// CHECK-NEXT: 401070: 68 08 00 00 00 pushl $8
+// CHECK-NEXT: 401075: e9 96 ff ff ff jmp -106 <.plt>
+// CHECK-NEXT: 40107a: cc int3
+// CHECK-NEXT: 40107b: cc int3
+// CHECK-NEXT: 40107c: cc int3
+// CHECK-NEXT: 40107d: cc int3
+// CHECK-NEXT: 40107e: cc int3
+// CHECK-NEXT: 40107f: cc int3
// CHECK: Contents of section .got.plt:
-// CHECK-NEXT: 00300100 00000000 00000000 50100100
-// CHECK-NEXT: 70100100
+// CHECK-NEXT: 00304000 00000000 00000000 50104000
+// CHECK-NEXT: 70104000
.global _start
_start:
diff --git a/test/ELF/icf13.s b/test/ELF/icf13.s
index 2fe707f11c76..c0d4935cca40 100644
--- a/test/ELF/icf13.s
+++ b/test/ELF/icf13.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/ELF/icf15.s b/test/ELF/icf15.s
index 57c1735e1518..5c651fbd65ff 100644
--- a/test/ELF/icf15.s
+++ b/test/ELF/icf15.s
@@ -1,3 +1,4 @@
+# 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
diff --git a/test/ELF/icf16.s b/test/ELF/icf16.s
index e7650af37c3b..13cb8ecd2994 100644
--- a/test/ELF/icf16.s
+++ b/test/ELF/icf16.s
@@ -1,3 +1,4 @@
+# REQUIRES: x86
# 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
diff --git a/test/ELF/icf17.s b/test/ELF/icf17.s
index 5d28aeb869c1..cab5c12d214e 100644
--- a/test/ELF/icf17.s
+++ b/test/ELF/icf17.s
@@ -1,3 +1,4 @@
+# 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
diff --git a/test/ELF/image-base.s b/test/ELF/image-base.s
index eb79acdced81..8866708c4001 100644
--- a/test/ELF/image-base.s
+++ b/test/ELF/image-base.s
@@ -3,6 +3,9 @@
# RUN: ld.lld -image-base=0x1000000 %t -o %t1
# RUN: llvm-readobj -program-headers %t1 | FileCheck %s
+# RUN: not ld.lld -image-base=ABC %t -o %t1 2>&1 | FileCheck --check-prefix=ERR %s
+# ERR: error: -image-base: number expected, but got ABC
+
# RUN: ld.lld -image-base=0x1000 -z max-page-size=0x2000 %t -o %t1 2>&1 | FileCheck --check-prefix=WARN %s
# WARN: warning: -image-base: address isn't multiple of page size: 0x1000
diff --git a/test/ELF/incompatible-ar-first.s b/test/ELF/incompatible-ar-first.s
index fbbe9de761ec..e49171939513 100644
--- a/test/ELF/incompatible-ar-first.s
+++ b/test/ELF/incompatible-ar-first.s
@@ -1,5 +1,6 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive.s -o %ta.o
+// RUN: rm -f %t.a
// 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 -o /dev/null 2>&1 | FileCheck %s
diff --git a/test/ELF/incompatible.s b/test/ELF/incompatible.s
index 44c5b4bfcbf7..283146a7ee4f 100644
--- a/test/ELF/incompatible.s
+++ b/test/ELF/incompatible.s
@@ -48,6 +48,7 @@
// We used to fail to identify this incompatibility and crash trying to
// read a 64 bit file as a 32 bit one.
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o
+// RUN: rm -f %t.a
// 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 -o %t | FileCheck --check-prefix=ARCHIVE %s
diff --git a/test/ELF/invalid-linkerscript.test b/test/ELF/invalid-linkerscript.test
index f9fb8478251f..e635ae4f2af9 100644
--- a/test/ELF/invalid-linkerscript.test
+++ b/test/ELF/invalid-linkerscript.test
@@ -50,5 +50,11 @@
# RUN: echo "OUTPUT_FORMAT(x y z)" > %t8
# RUN: not ld.lld %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
-# ERR8: , expected, but got y
+# RUN: not ld.lld -m elf_amd64 %t8 no-such-file 2>&1 | FileCheck -check-prefix=ERR8 %s
+# ERR8: unknown output format name: x
# ERR8: cannot open no-such-file:
+
+# RUN: echo "OUTPUT_FORMAT(elf64-x86-64 y z)" > %t9
+# RUN: not ld.lld %t9 no-such-file 2>&1 | FileCheck -check-prefix=ERR9 %s
+# ERR9: , expected, but got y
+# ERR9: cannot open no-such-file:
diff --git a/test/ELF/invalid/Inputs/shentsize-zero.elf b/test/ELF/invalid/Inputs/shentsize-zero.elf
deleted file mode 100644
index 5fa7df245619..000000000000
--- a/test/ELF/invalid/Inputs/shentsize-zero.elf
+++ /dev/null
Binary files differ
diff --git a/test/ELF/invalid/Inputs/sht-group.elf b/test/ELF/invalid/Inputs/sht-group.elf
deleted file mode 100644
index 5cb033628418..000000000000
--- a/test/ELF/invalid/Inputs/sht-group.elf
+++ /dev/null
Binary files differ
diff --git a/test/ELF/invalid/Inputs/undefined-local-symbol-in-dso.so b/test/ELF/invalid/Inputs/undefined-local-symbol-in-dso.so
new file mode 100755
index 000000000000..b88427351197
--- /dev/null
+++ b/test/ELF/invalid/Inputs/undefined-local-symbol-in-dso.so
Binary files differ
diff --git a/test/ELF/invalid/comdat-broken.test b/test/ELF/invalid/comdat-broken.test
new file mode 100644
index 000000000000..9ff8eca476a5
--- /dev/null
+++ b/test/ELF/invalid/comdat-broken.test
@@ -0,0 +1,25 @@
+# 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 %t.o -o %t.exe 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.o: unsupported SHT_GROUP format
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ Info: foo
+ Members:
+ - SectionOrType: 0xFF
+ - SectionOrType: 3
+Symbols:
+ Global:
+ - Name: foo
diff --git a/test/ELF/invalid/ehframe-broken-relocation.test b/test/ELF/invalid/ehframe-broken-relocation.test
new file mode 100644
index 000000000000..1333a6d0a868
--- /dev/null
+++ b/test/ELF/invalid/ehframe-broken-relocation.test
@@ -0,0 +1,31 @@
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld --icf=all %t.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: .eh_frame: relocation is not in any piece
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .eh_frame
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC]
+ Content: "1400000000000000017a5200017810011b0c070890010000140000001c00000000000000000000000000000000000000"
+ - Name: .rela.eh_frame
+ Type: SHT_RELA
+ Link: .symtab
+ Info: .eh_frame
+ Relocations:
+ - Offset: 0x99999999
+ Symbol: zed
+ Type: R_X86_64_64
+Symbols:
+ Global:
+ - Name: zed
+ Type: STT_FUNC
+ Section: .eh_frame
+ Value: 0x0
+ Size: 8
diff --git a/test/ELF/invalid/invalid-soname.test b/test/ELF/invalid/invalid-soname.test
new file mode 100644
index 000000000000..8641465acd50
--- /dev/null
+++ b/test/ELF/invalid/invalid-soname.test
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.so
+# RUN: not ld.lld %t.so -o %t.exe 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.so: invalid DT_SONAME entry
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+Sections:
+ - Name: .test
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_ALLOC ]
+ Content: "0e000000000000000000000000000001"
+ Link: .strtab
diff --git a/test/ELF/invalid/linkorder-invalid-sec.test b/test/ELF/invalid/linkorder-invalid-sec.test
new file mode 100644
index 000000000000..d4aa376639c3
--- /dev/null
+++ b/test/ELF/invalid/linkorder-invalid-sec.test
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: invalid sh_link index: 12345
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .linkorder
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_LINK_ORDER ]
+ Link: 12345
diff --git a/test/ELF/invalid/linkorder-invalid-sec2.test b/test/ELF/invalid/linkorder-invalid-sec2.test
new file mode 100644
index 000000000000..f78df3fb0896
--- /dev/null
+++ b/test/ELF/invalid/linkorder-invalid-sec2.test
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: invalid sh_link index: 0
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .linkorder
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_LINK_ORDER ]
+ Link: 0
diff --git a/test/ELF/invalid/merge-invalid-size.s b/test/ELF/invalid/merge-invalid-size.s
index cc2566d0ee87..b16889a538a5 100644
--- a/test/ELF/invalid/merge-invalid-size.s
+++ b/test/ELF/invalid/merge-invalid-size.s
@@ -3,8 +3,5 @@
// 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 /dev/null
-
.section .foo,"aM",@progbits,4
.short 42
diff --git a/test/ELF/invalid/merge-zero-size.test b/test/ELF/invalid/merge-zero-size.test
new file mode 100644
index 000000000000..564ed44068ef
--- /dev/null
+++ b/test/ELF/invalid/merge-zero-size.test
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+
+# RUN: yaml2obj %s -o %t.o
+
+# Test that we accept a zero sh_entsize for SHF_MERGE section.
+# RUN: ld.lld %t.o -o %t.exe
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .strings
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x04
+ Content: "FFFFFFFFFFFFFFFF"
+ EntSize: 0x0
diff --git a/test/ELF/invalid/non-terminated-string.test b/test/ELF/invalid/non-terminated-string.test
new file mode 100644
index 000000000000..82e94fe1457c
--- /dev/null
+++ b/test/ELF/invalid/non-terminated-string.test
@@ -0,0 +1,19 @@
+# RUN: yaml2obj %s -o %t
+# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s
+
+# CHECK: {{.*}}:(.merge): string is not null terminated
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_FREEBSD
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Type: SHT_PROGBITS
+ Name: .merge
+ Flags: [ SHF_ALLOC, SHF_MERGE, SHF_STRINGS ]
+ AddressAlign: 0x04
+ Content: "AABB"
+ EntSize: 0x2
diff --git a/test/ELF/invalid/sht-group-wrong-section.test b/test/ELF/invalid/sht-group-wrong-section.test
new file mode 100644
index 000000000000..d431dcbc2d24
--- /dev/null
+++ b/test/ELF/invalid/sht-group-wrong-section.test
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o %t.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}.o: invalid section index in group: 12345
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ Info: foo
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: 12345
+Symbols:
+ Global:
+ - Name: foo
diff --git a/test/ELF/invalid/sht-group.s b/test/ELF/invalid/sht-group.s
deleted file mode 100644
index a4b684c83fd3..000000000000
--- a/test/ELF/invalid/sht-group.s
+++ /dev/null
@@ -1,3 +0,0 @@
-## sht-group.elf contains SHT_GROUP section with invalid sh_info.
-# 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/sht-group.test b/test/ELF/invalid/sht-group.test
new file mode 100644
index 000000000000..c91e649e2643
--- /dev/null
+++ b/test/ELF/invalid/sht-group.test
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s
+# CHECK: invalid symbol index
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ Info: 12345
+ Members:
+ - SectionOrType: GRP_COMDAT
diff --git a/test/ELF/invalid/undefined-local-symbol-in-dso.test b/test/ELF/invalid/undefined-local-symbol-in-dso.test
new file mode 100644
index 000000000000..a9c30f30db6f
--- /dev/null
+++ b/test/ELF/invalid/undefined-local-symbol-in-dso.test
@@ -0,0 +1,66 @@
+# REQUIRES: x86
+
+# LLD used to crash when linking against a DSO with an undefined STB_LOCAL
+# symbol in the global part of the dynamic symbol table (i.e. an STB_LOCAL
+# symbol with an index >= the sh_info of the dynamic symbol table section). Such
+# a DSO is very broken, because local symbols should precede all global symbols
+# in the symbol table, and because having a symbol that's both undefined and
+# STB_LOCAL is a nonsensical combination. Nevertheless, we should warn on such
+# input files instead of crashing.
+
+# We've found actual broken DSOs of this sort in the wild, but for this test, we
+# created a reduced broken input file. There are no tools capable of producing a
+# broken DSO of this nature, so instead we created a valid DSO with an undefined
+# global symbol in the dynamic symbol table and then manually edited the binary
+# to make that symbol local. The valid DSO was created as follows:
+
+```
+% cat undef.s
+.hidden bar
+bar:
+ movq foo@GOT, %rax
+
+% llvm-mc -triple=x86_64-linux-gnu -filetype=obj -o undef.o undef.s
+% ld.lld --no-rosegment -shared -o undefined-local-symbol-in-dso.so undef.o
+% strip undef.so
+```
+
+# (--no-rosegment and stripping are unnecessary; they just produce a smaller
+# binary)
+
+# This DSO should only have a single dynamic symbol table entry for foo, and
+# then we can use a small C program to modify that symbol table entry to be
+# STB_LOCAL instead of STB_GLOBAL.
+
+```
+#include <elf.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ FILE *F = fopen(argv[1], "rb+");
+
+ Elf64_Ehdr Ehdr;
+ fread(&Ehdr, sizeof(Ehdr), 1, F);
+ fseek(F, Ehdr.e_shoff, SEEK_SET);
+
+ Elf64_Shdr Shdr;
+ do {
+ fread(&Shdr, sizeof(Shdr), 1, F);
+ } while (Shdr.sh_type != SHT_DYNSYM);
+
+ Elf64_Sym Sym;
+ fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET);
+ fread(&Sym, sizeof(Sym), 1, F);
+ Sym.st_info = STB_LOCAL << 4 | ELF64_ST_TYPE(Sym.st_info);
+ fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET);
+ fwrite(&Sym, sizeof(Sym), 1, F);
+ fclose(F);
+}
+```
+
+# (the C program just takes its input DSO and modifies the binding of the first
+# dynamic symbol table entry to be STB_LOCAL instead of STB_GLOBAL)
+
+# RUN: ld.lld %p/Inputs/undefined-local-symbol-in-dso.so -o %t 2>&1 | \
+# RUN: FileCheck -check-prefix=WARN %s
+# WARN: found local symbol 'foo' in global part of symbol table in file {{.*}}undefined-local-symbol-in-dso.so
diff --git a/test/ELF/lazy-arch-conflict.s b/test/ELF/lazy-arch-conflict.s
new file mode 100644
index 000000000000..e17c301798f1
--- /dev/null
+++ b/test/ELF/lazy-arch-conflict.s
@@ -0,0 +1,7 @@
+# REQUIRES: x86
+
+# RUN: echo '.globl foo; .weak foo; .quad foo;' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t64.o
+# RUN: echo '.globl foo; foo:' | llvm-mc -filetype=obj -triple=i686-pc-linux - -o %t32.o
+# RUN: not ld.lld %t64.o --start-lib %t32.o --end-lib -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: incompatible file: {{.*}}32.o
diff --git a/test/ELF/linkerscript/Inputs/at6.s b/test/ELF/linkerscript/Inputs/at6.s
new file mode 100644
index 000000000000..2d22d4d342dd
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/at6.s
@@ -0,0 +1,11 @@
+.global _start
+.text
+_start:
+nop
+
+.section .sec1,"aw",@progbits
+.long 1
+
+.section .sec2,"aw",@progbits
+.long 2
+
diff --git a/test/ELF/linkerscript/Inputs/at7.s b/test/ELF/linkerscript/Inputs/at7.s
new file mode 100644
index 000000000000..29d29635963b
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/at7.s
@@ -0,0 +1,7 @@
+.global _start
+.text
+_start:
+nop
+
+.section .sec, "aw"
+.word 4
diff --git a/test/ELF/linkerscript/Inputs/at8.s b/test/ELF/linkerscript/Inputs/at8.s
new file mode 100644
index 000000000000..e15e4cd3b77f
--- /dev/null
+++ b/test/ELF/linkerscript/Inputs/at8.s
@@ -0,0 +1,8 @@
+.section .sec1,"aw",@progbits
+.quad 1
+
+.section .sec2,"aw",@progbits
+.quad 2
+
+.section .sec3,"aw",@progbits
+.quad 3
diff --git a/test/ELF/linkerscript/align-r.test b/test/ELF/linkerscript/align-r.test
index 684ac1e92328..5bde8950974f 100644
--- a/test/ELF/linkerscript/align-r.test
+++ b/test/ELF/linkerscript/align-r.test
@@ -4,7 +4,7 @@
# 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
+# RUN: llvm-readelf -S %t2.o | FileCheck %s
# CHECK: Section Headers:
# CHECK-NEXT: Name Type Address Off Size ES Flg Lk Inf Al
diff --git a/test/ELF/linkerscript/align4.test b/test/ELF/linkerscript/align4.test
index 9440d60f6385..834e843da82b 100644
--- a/test/ELF/linkerscript/align4.test
+++ b/test/ELF/linkerscript/align4.test
@@ -4,7 +4,6 @@
# 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
diff --git a/test/ELF/linkerscript/at6.test b/test/ELF/linkerscript/at6.test
new file mode 100644
index 000000000000..498c0ef14f34
--- /dev/null
+++ b/test/ELF/linkerscript/at6.test
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at6.s -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t
+# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s
+
+MEMORY {
+ FLASH : ORIGIN = 0x08000000, LENGTH = 0x100
+ RAM : ORIGIN = 0x20000000, LENGTH = 0x200
+}
+
+SECTIONS {
+ .text : { *(.text) } > FLASH
+ .sec1 : { *(.sec1) } > RAM
+ .sec2 : { *(.sec2) } > RAM AT > FLASH
+}
+
+# Make sure we create a separate PT_LOAD entry for .sec2. Previously,
+# it was added to the PT_LOAD entry of .sec1
+
+# CHECK: Name Type Address Off
+# CHECK: .text PROGBITS 0000000008000000 001000
+# CHECK: .sec1 PROGBITS 0000000020000000 002000
+# CHECK: .sec2 PROGBITS 0000000020000004 002004
+
+# CHECK: Program Headers:
+# CHECK: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: LOAD 0x001000 0x0000000008000000 0x0000000008000000
+# CHECK-NEXT: LOAD 0x002000 0x0000000020000000 0x0000000020000000
+# CHECK-NEXT: LOAD 0x002004 0x0000000020000004 0x0000000008000001
+# CHECK-NOT: LOAD
diff --git a/test/ELF/linkerscript/at7.test b/test/ELF/linkerscript/at7.test
new file mode 100644
index 000000000000..1f67df29fdcd
--- /dev/null
+++ b/test/ELF/linkerscript/at7.test
@@ -0,0 +1,28 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at7.s -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t
+# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s
+
+MEMORY {
+ RAM : ORIGIN = 0x20000000, LENGTH = 0x200
+}
+
+SECTIONS {
+ .text : { *(.text) } > RAM AT> RAM
+ .sec : { *(.sec) } > RAM
+}
+
+# Make sure the memory for the .text section is only reserved once.
+# Previously, the location counter for both MemRegion and LMARegion
+# was increased unconditionally.
+
+
+# CHECK: Name Type Address Off
+# CHECK: .text PROGBITS 0000000020000000 001000
+# CHECK: .sec PROGBITS 0000000020000001 001001
+
+# CHECK: Program Headers:
+# CHECK: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: LOAD 0x001000 0x0000000020000000 0x0000000020000000
+# CHECK-NEXT: LOAD 0x001001 0x0000000020000001 0x0000000020000001
+# CHECK-NOT: LOAD
diff --git a/test/ELF/linkerscript/at8.test b/test/ELF/linkerscript/at8.test
new file mode 100644
index 000000000000..48c0d4581422
--- /dev/null
+++ b/test/ELF/linkerscript/at8.test
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at8.s -o %t.o
+# RUN: ld.lld %t.o --script %s -o %t
+# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s
+
+MEMORY {
+ FLASH : ORIGIN = 0x08000000, LENGTH = 0x100
+ RAM : ORIGIN = 0x20000000, LENGTH = 0x200
+}
+
+SECTIONS {
+ .text : { *(.text) } > FLASH
+ .sec1 : { *(.sec1) } > RAM AT > FLASH
+ .sec2 : { *(.sec2) } > RAM
+ .sec3 : { *(.sec3) } > RAM AT > FLASH
+}
+
+# Make sure we do not issue a load-address overlap error
+# Previously, .sec3 would overwrite the LMAOffset in the
+# PT_LOAD header.
+
+# CHECK: Name Type Address Off
+# CHECK: .text PROGBITS 0000000008000000 001000
+# CHECK: .sec1 PROGBITS 0000000020000000 001000
+# CHECK: .sec2 PROGBITS 0000000020000008 001008
+# CHECK: .sec3 PROGBITS 0000000020000010 001010
+
+# CHECK: Program Headers:
+# CHECK: Type Offset VirtAddr PhysAddr
+# CHECK-NEXT: LOAD 0x001000 0x0000000020000000 0x0000000008000000
+# CHECK-NOT: LOAD
diff --git a/test/ELF/linkerscript/discard-section-err.s b/test/ELF/linkerscript/discard-section-err.s
index f1d3b96691ba..bb77dbb087da 100644
--- a/test/ELF/linkerscript/discard-section-err.s
+++ b/test/ELF/linkerscript/discard-section-err.s
@@ -7,25 +7,17 @@
# RUN: FileCheck -check-prefix=SHSTRTAB %s
# SHSTRTAB: discarding .shstrtab section is not allowed
+## We allow discarding .dynamic, check we don't crash.
# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynamic) } }" > %t.script
-# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
-# RUN: FileCheck -check-prefix=DYNAMIC %s
-# DYNAMIC: discarding .dynamic section is not allowed
+# RUN: ld.lld -pie -o %t --script %t.script %t.o
+## We allow discarding .dynsym, check we don't crash.
# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynsym) } }" > %t.script
-# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
-# RUN: FileCheck -check-prefix=DYNSYM %s
-# DYNSYM: discarding .dynsym section is not allowed
+# RUN: ld.lld -pie -o %t --script %t.script %t.o
+## We allow discarding .dynstr, check we don't crash.
# RUN: echo "SECTIONS { /DISCARD/ : { *(.dynstr) } }" > %t.script
-# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
-# 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: ld.lld -pie -o %t --script %t.script %t.o
# RUN: echo "SECTIONS { /DISCARD/ : { *(.rela.dyn) } }" > %t.script
# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \
diff --git a/test/ELF/linkerscript/filename-spec.s b/test/ELF/linkerscript/filename-spec.s
index 66fd4178387c..8a1f6605e2a9 100644
--- a/test/ELF/linkerscript/filename-spec.s
+++ b/test/ELF/linkerscript/filename-spec.s
@@ -43,6 +43,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.testdir1/filename-spec1.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
# RUN: %p/Inputs/filename-spec.s -o %t.testdir2/filename-spec2.o
+# RUN: rm -f %t.testdir1/lib1.a %t.testdir2/lib2.a
# RUN: llvm-ar rsc %t.testdir1/lib1.a %t.testdir1/filename-spec1.o
# RUN: llvm-ar rsc %t.testdir2/lib2.a %t.testdir2/filename-spec2.o
diff --git a/test/ELF/linkerscript/icf.s b/test/ELF/linkerscript/icf.s
new file mode 100644
index 000000000000..7c74458232aa
--- /dev/null
+++ b/test/ELF/linkerscript/icf.s
@@ -0,0 +1,11 @@
+# REQUIRES: x86
+
+# RUN: echo "foo = 1; bar = 2;" > %t.script
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.script -o %t --icf=all --print-icf-sections | count 0
+
+.section .text.foo,"ax",@progbits
+jmp foo
+
+.section .text.bar,"ax",@progbits
+jmp bar
diff --git a/test/ELF/linkerscript/info-section-type.s b/test/ELF/linkerscript/info-section-type.s
index b718e828ab7d..16e663fc5d0f 100644
--- a/test/ELF/linkerscript/info-section-type.s
+++ b/test/ELF/linkerscript/info-section-type.s
@@ -29,5 +29,14 @@
# RUN: ld.lld -o %t --script %t.script %t.o
# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC
+# RUN: echo "SECTIONS { .bar 0x20000 (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 0x20000 (BAR) : { *(.foo) } };" > %t.script
+# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 |\
+# RUN: FileCheck %s --check-prefix=UNKNOWN
+# UNKNOWN: unknown section directive: BAR
+
.section .foo,"a",@progbits
.zero 1
diff --git a/test/ELF/linkerscript/lazy-symbols.test b/test/ELF/linkerscript/lazy-symbols.test
index 579df9323865..f409b839c4dd 100644
--- a/test/ELF/linkerscript/lazy-symbols.test
+++ b/test/ELF/linkerscript/lazy-symbols.test
@@ -1,5 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/lazy-symbols.s -o %t1
+# RUN: rm -f %tar
# RUN: llvm-ar rcs %tar %t1
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t2
# RUN: ld.lld %t2 %tar --script %s -o %tout
diff --git a/test/ELF/linkerscript/map-file.test b/test/ELF/linkerscript/map-file.test
index 540b8d494887..6ec8bafc42b1 100644
--- a/test/ELF/linkerscript/map-file.test
+++ b/test/ELF/linkerscript/map-file.test
@@ -44,10 +44,10 @@ SECTIONS {
# 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: 225d 225d 0 1 sym1 = .
+# CHECK-NEXT: 225d 225d 500 1 . += 0x500
+# CHECK-NEXT: 275d 275d 0 1 sym2 = .
+# CHECK-NEXT: 275d 275d 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
diff --git a/test/ELF/linkerscript/map-file2.test b/test/ELF/linkerscript/map-file2.test
index d9ed339e228d..535043282249 100644
--- a/test/ELF/linkerscript/map-file2.test
+++ b/test/ELF/linkerscript/map-file2.test
@@ -8,6 +8,7 @@ SECTIONS {
.aaa : { *(.aaa.*) }
.bbb : AT(0x2000) { *(.bbb.*) }
.ccc : AT(0x3000) { *(.ccc.*) }
+ . += 0x100;
.ddd : {
BYTE(0x11)
. += 0x100;
@@ -24,16 +25,17 @@ SECTIONS {
# 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: 1018 3008 100 1 . += 0x100
+# CHECK-NEXT: 1118 3108 109 1 .ddd
+# CHECK-NEXT: 1118 3108 1 1 BYTE ( 0x11 )
+# CHECK-NEXT: 1119 3109 100 1 . += 0x100
+# CHECK-NEXT: 1219 3209 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd)
+# CHECK-NEXT: 1228 3218 34 8 .eh_frame
+# CHECK-NEXT: 1228 3218 30 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.eh_frame+0x0)
+# CHECK-NEXT: 125c 324c 1 4 .text
+# CHECK-NEXT: 125c 324c 1 4 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.text)
+# CHECK-NEXT: 125c 324c 0 1 f(int)
+# CHECK-NEXT: 125c 324c 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
diff --git a/test/ELF/linkerscript/memory-include.test b/test/ELF/linkerscript/memory-include.test
new file mode 100644
index 000000000000..340328225bde
--- /dev/null
+++ b/test/ELF/linkerscript/memory-include.test
@@ -0,0 +1,23 @@
+# REQUIRES: x86
+
+# RUN: echo '.section .text,"ax"; .global _start; nop' > %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.o
+
+# RUN: echo "RAM2 (rwx): ORIGIN = 0x3000, LENGTH = 0x100" > %t.inc
+# RUN: ld.lld -o %t.elf --script %s %t.o -L %T
+# RUN: llvm-objdump -section-headers %t.elf | FileCheck %s
+# CHECK: .data 00000008 0000000000002000 DATA
+# CHECK: .data2 00000008 0000000000003000 DATA
+
+MEMORY {
+ ROM (rwx): ORIGIN = 0x1000, LENGTH = 0x100
+ RAM (rwx): ORIGIN = 0x2000, LENGTH = 0x100
+ INCLUDE "memory-include.test.tmp.inc"
+}
+
+SECTIONS {
+ .text : { *(.text*) } > ROM
+ .data : { *(.data*) } > RAM
+ .data2 : { QUAD(0) } > RAM2
+}
diff --git a/test/ELF/linkerscript/merge-nonalloc.s b/test/ELF/linkerscript/merge-nonalloc.s
new file mode 100644
index 000000000000..7c48d3bc6cd0
--- /dev/null
+++ b/test/ELF/linkerscript/merge-nonalloc.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { *(.text) *(.nonalloc) } }" > %t.script
+# RUN: ld.lld -shared -o %t.exe %t.script %t.o
+# RUN: llvm-objdump -syms %t.exe | FileCheck %s
+
+# CHECK: .text 00000000 nonalloc_start
+
+_start:
+ nop
+
+.section .nonalloc,"",@progbits
+nonalloc_start:
+ .long 0xcafe
diff --git a/test/ELF/linkerscript/no-filename-spec.s b/test/ELF/linkerscript/no-filename-spec.s
new file mode 100644
index 000000000000..aec03958da7d
--- /dev/null
+++ b/test/ELF/linkerscript/no-filename-spec.s
@@ -0,0 +1,17 @@
+# REQUIRES: x86
+# RUN: echo '.section .bar, "a"; .quad 1;' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %tfile1.o
+# RUN: echo '.section .zed, "a"; .quad 2;' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %tfile2.o
+
+## We have a file name and no input sections description. In that case, all
+## sections from the file specified should be included. Check that.
+# RUN: ld.lld -o %t --script %s %tfile1.o %tfile2.o
+# RUN: llvm-objdump -s %t | FileCheck %s
+
+# CHECK: Contents of section .foo:
+# CHECK-NEXT: 01000000 00000000 02000000 00000000
+
+SECTIONS {
+ .foo : { *file1.o *file2.o }
+}
diff --git a/test/ELF/linkerscript/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s
index d9984b3867d4..143cac1e2b12 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-readelf -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 87f9afff8091..e6fb84d17d41 100644
--- a/test/ELF/linkerscript/non-alloc.s
+++ b/test/ELF/linkerscript/non-alloc.s
@@ -3,7 +3,7 @@
# RUN: echo "SECTIONS { .foo 0 : {*(foo)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
-# RUN: llvm-readelf -s -l %t | FileCheck %s
+# 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.
diff --git a/test/ELF/linkerscript/orphan-discard.s b/test/ELF/linkerscript/orphan-discard.s
index 6fd6fafcd7f4..4549c3bc2b9e 100644
--- a/test/ELF/linkerscript/orphan-discard.s
+++ b/test/ELF/linkerscript/orphan-discard.s
@@ -10,7 +10,7 @@
# RUN: /DISCARD/ : { *(.comment) } \
# RUN: }" > %t.script
# RUN: ld.lld -o %t --script %t.script %t.o
-# RUN: llvm-readelf -s -symbols %t | FileCheck %s
+# RUN: llvm-readelf -S -symbols %t | FileCheck %s
# CHECK: .bss NOBITS ffffffff80002000 002008 000002 00 WA 0 0 4096
# CHECK: ffffffff80003000 0 NOTYPE GLOBAL DEFAULT 3 _end
diff --git a/test/ELF/linkerscript/orphan-phdrs.s b/test/ELF/linkerscript/orphan-phdrs.s
index f9d1467b532a..c889562d0fcc 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-readelf -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.
diff --git a/test/ELF/linkerscript/ouputformat.s b/test/ELF/linkerscript/ouputformat.s
deleted file mode 100644
index 7d4402a557a0..000000000000
--- a/test/ELF/linkerscript/ouputformat.s
+++ /dev/null
@@ -1,9 +0,0 @@
-# REQUIRES: x86
-# RUN: echo "OUTPUT_FORMAT(x, y, z)" > %t.script
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
-# RUN: ld.lld -shared -o %t2 %t1 %t.script
-# RUN: llvm-readobj %t2 > /dev/null
-
-# RUN: echo "OUTPUT_FORMAT(x, y)" > %t.script
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1
-# RUN: not ld.lld -shared -o %t2 %t1 %t.script
diff --git a/test/ELF/linkerscript/output-section-include.test b/test/ELF/linkerscript/output-section-include.test
new file mode 100644
index 000000000000..b18a7ee037a3
--- /dev/null
+++ b/test/ELF/linkerscript/output-section-include.test
@@ -0,0 +1,30 @@
+# REQUIRES: x86
+
+# RUN: echo '.section .text,"ax"; .global _start; nop' > %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.o
+
+## Empty include file.
+# RUN: echo "" > %t.inc
+# RUN: ld.lld -o %t.elf --script %s %t.o -L %T
+# RUN: llvm-objdump -section-headers %t.elf | FileCheck %s --check-prefix=CHECK1
+# CHECK1: .data 00000008 0000000000002000 DATA
+
+## Non-empty include file.
+# RUN: echo "QUAD(0)" > %t.inc
+# RUN: ld.lld -o %t.elf --script %s %t.o -L %T
+# RUN: llvm-objdump -section-headers %t.elf | FileCheck %s --check-prefix=CHECK2
+# CHECK2: .data 00000010 0000000000002000 DATA
+
+MEMORY {
+ ROM (rwx): ORIGIN = 0x1000, LENGTH = 0x100
+ RAM (rwx): ORIGIN = 0x2000, LENGTH = 0x100
+}
+
+SECTIONS {
+ .text : { *(.text*) } > ROM
+ .data : {
+ *(.data*)
+ INCLUDE "output-section-include.test.tmp.inc"
+ } > RAM
+}
diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s
index ca85465036fe..a5130d27a070 100644
--- a/test/ELF/linkerscript/output-too-large.s
+++ b/test/ELF/linkerscript/output-too-large.s
@@ -1,7 +1,13 @@
# 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 --no-check-sections --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { .text : { . = 0x8fffffffffffffff; *(.text*); } }" > %t.script
+# 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/phdrs.s b/test/ELF/linkerscript/phdrs.s
index b65015994533..c688bef5282c 100644
--- a/test/ELF/linkerscript/phdrs.s
+++ b/test/ELF/linkerscript/phdrs.s
@@ -130,6 +130,14 @@
# BADHDR: {{.*}}.script:1: section header 'bar' is not listed in PHDRS
+# RUN: echo "PHDRS { text PT_LOAD FOOHDR; }" > %t1.script
+# RUN: not ld.lld -o /dev/null --script %t1.script %t 2>&1 | FileCheck --check-prefix=FOOHDR %s
+# FOOHDR: error: {{.*}}.script:1: unexpected header attribute: FOOHDR
+
+# RUN: echo "PHDRS { text PT_FOO FOOHDR; }" > %t1.script
+# RUN: not ld.lld -o /dev/null --script %t1.script %t 2>&1 | FileCheck --check-prefix=PTFOO %s
+# PTFOO: invalid program header type: PT_FOO
+
.global _start
_start:
nop
diff --git a/test/ELF/linkerscript/provide-shared2.s b/test/ELF/linkerscript/provide-shared2.s
index 8a3200b6f545..1a7b213d8e54 100644
--- a/test/ELF/linkerscript/provide-shared2.s
+++ b/test/ELF/linkerscript/provide-shared2.s
@@ -6,7 +6,7 @@
# 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@
+# CHECK: 1 1: 000000000000002a 0 NOTYPE GLOBAL DEFAULT ABS foo
.global _start
_start:
diff --git a/test/ELF/linkerscript/relocatable-discard.s b/test/ELF/linkerscript/relocatable-discard.s
new file mode 100644
index 000000000000..d4f5826b72d9
--- /dev/null
+++ b/test/ELF/linkerscript/relocatable-discard.s
@@ -0,0 +1,21 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "SECTIONS { /DISCARD/ : { *(.discard.*) }}" > %t.script
+# RUN: ld.lld -o %t --script %t.script -r %t.o
+# RUN: llvm-readobj -sections %t | FileCheck %s
+
+## Test shows that we do not crash after discarding the .discard.foo with -r.
+## Previously it happened because of 2 reasons:
+## 1) .rela.discard.foo was not handled properly and was not discarded.
+## Remaining reference was invalid and caused the crash.
+## 2) Third-party section .debug_info referencing discarded section
+## did not handle this case properly and tried to apply the
+## relocation instead of ignoring it.
+
+# CHECK-NOT: .discard
+
+.section .discard.foo,"ax"
+callq fn@PLT
+
+.section .debug_info,"",@progbits
+.long .discard.foo
diff --git a/test/ELF/linkerscript/section-include.test b/test/ELF/linkerscript/section-include.test
new file mode 100644
index 000000000000..9b6dfa0dcc4e
--- /dev/null
+++ b/test/ELF/linkerscript/section-include.test
@@ -0,0 +1,32 @@
+# REQUIRES: x86
+
+# RUN: echo '.section .text,"ax"; .global _start; nop' > %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.o
+
+## Empty include file.
+# RUN: echo "" > %t.inc
+# RUN: ld.lld -o %t.elf --script %s %t.o -L %T
+# RUN: llvm-objdump -section-headers %t.elf | FileCheck %s --check-prefix=CHECK1
+# CHECK1: .data 00000008 0000000000002000 DATA
+# CHECK1-NEXT: .data3 00000008 0000000000002008 DATA
+
+## Non-empty include file.
+# RUN: echo ".data2 : { QUAD(0) } > RAM" > %t.inc
+# RUN: ld.lld -o %t.elf --script %s %t.o -L %T
+# RUN: llvm-objdump -section-headers %t.elf | FileCheck %s --check-prefix=CHECK2
+# CHECK2: .data 00000008 0000000000002000 DATA
+# CHECK2-NEXT: .data2 00000008 0000000000002008 DATA
+# CHECK2-NEXT: .data3 00000008 0000000000002010 DATA
+
+MEMORY {
+ ROM (rwx): ORIGIN = 0x1000, LENGTH = 0x100
+ RAM (rwx): ORIGIN = 0x2000, LENGTH = 0x100
+}
+
+SECTIONS {
+ .text : { *(.text*) } > ROM
+ .data : { *(.data*) } > RAM
+ INCLUDE "section-include.test.tmp.inc"
+ .data3 : { QUAD(0) } > RAM
+}
diff --git a/test/ELF/linkerscript/sections-va-overflow.test b/test/ELF/linkerscript/sections-va-overflow.test
index 7ede6ecc3de8..142d2e5ef2d7 100644
--- a/test/ELF/linkerscript/sections-va-overflow.test
+++ b/test/ELF/linkerscript/sections-va-overflow.test
@@ -7,7 +7,7 @@ PHDRS {
ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4);
}
-SECTIONS {
+SECTIONS {
. = 0xffffffff20000000;
.text : { *(.text*) } : ph_text
.test 0x1000 : { BYTE(0) }
@@ -18,5 +18,5 @@ SECTIONS {
## 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: error: unable to place section .text at file offset [0xFFFFFFFF20000000, 0xFFFFFFFF20000000]; check your linker script for overflows
# ERR-NOT: unable to place section .bss
diff --git a/test/ELF/linkerscript/segment-none.s b/test/ELF/linkerscript/segment-none.s
index 06566525caf7..36d09e776478 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-readelf -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-readelf -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/sizeof.s b/test/ELF/linkerscript/sizeof.s
index 4618f79d3db6..0d7106fc8956 100644
--- a/test/ELF/linkerscript/sizeof.s
+++ b/test/ELF/linkerscript/sizeof.s
@@ -18,7 +18,6 @@
# CHECK-NEXT: 2 .bbb 00000010
# CHECK-NEXT: 3 .ccc 00000018
# CHECK: SYMBOL TABLE:
-# CHECK-NEXT: 0000000000000000 *UND* 00000000
# CHECK-NEXT: .text 00000000 _start
# CHECK-NEXT: 0000000000000008 *ABS* 00000000 _aaa
# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb
diff --git a/test/ELF/linkerscript/sizeofheaders.s b/test/ELF/linkerscript/sizeofheaders.s
index 3cc70747280c..6a82442bc938 100644
--- a/test/ELF/linkerscript/sizeofheaders.s
+++ b/test/ELF/linkerscript/sizeofheaders.s
@@ -9,7 +9,6 @@
# RUN: llvm-objdump -t %t1 | FileCheck %s
#CHECK: SYMBOL TABLE:
-#CHECK-NEXT: 0000000000000000 *UND* 00000000
#CHECK-NEXT: 00000000000000e8 .text 00000000 _start
#CHECK-NEXT: 00000000000000e8 *ABS* 00000000 _size
diff --git a/test/ELF/linkerscript/sort-init.s b/test/ELF/linkerscript/sort-init.s
index 894b8ae882b7..dd030ace2efb 100644
--- a/test/ELF/linkerscript/sort-init.s
+++ b/test/ELF/linkerscript/sort-init.s
@@ -1,16 +1,18 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
-# RUN: echo "SECTIONS { .init_array : { *(SORT_BY_INIT_PRIORITY(.init_array.*)) } }" > %t1.script
+# RUN: echo "SECTIONS { .init_array : { *(SORT_BY_INIT_PRIORITY(.init_array.* foo*)) } }" > %t1.script
# RUN: ld.lld --script %t1.script %t1.o -o %t2
# RUN: llvm-objdump -s %t2 | FileCheck %s
# CHECK: Contents of section .init_array:
-# CHECK-NEXT: 03020000 00000000 010405
+# CHECK-NEXT: 03020000 00060000 010405
.globl _start
_start:
nop
+.section foo, "aw", @init_array
+ .byte 6
.section .init_array, "aw", @init_array
.align 8
.byte 1
diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s
index 2477c835e134..7207e90d4d76 100644
--- a/test/ELF/linkerscript/sort-non-script.s
+++ b/test/ELF/linkerscript/sort-non-script.s
@@ -3,7 +3,7 @@
# RUN: echo "SECTIONS { foo : {*(foo)} }" > %t.script
# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared
-# RUN: llvm-readelf -s %t | FileCheck %s
+# RUN: llvm-readelf -S %t | FileCheck %s
# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .hash {{.*}} A
diff --git a/test/ELF/linkerscript/symbol-assignexpr.s b/test/ELF/linkerscript/symbol-assignexpr.s
index 3be7d05931fe..56e0827caf11 100644
--- a/test/ELF/linkerscript/symbol-assignexpr.s
+++ b/test/ELF/linkerscript/symbol-assignexpr.s
@@ -25,7 +25,6 @@
# RUN: llvm-objdump -t %t1 | FileCheck %s
# CHECK: SYMBOL TABLE:
-# CHECK-NEXT: 0000000000000000 *UND* 00000000
# CHECK-NEXT: 0000000000000000 .text 00000000 _start
# CHECK-NEXT: 0000000000005678 *ABS* 00000000 bar
# CHECK-NEXT: 0000000000009abc *ABS* 00000000 baz
diff --git a/test/ELF/linkerscript/symbol-location.s b/test/ELF/linkerscript/symbol-location.s
new file mode 100644
index 000000000000..323d237e1533
--- /dev/null
+++ b/test/ELF/linkerscript/symbol-location.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "foo = 1;" > %t.script
+# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | FileCheck %s
+
+## Here we check that symbol 'foo' location is reported properly.
+
+# CHECK: error: relocation R_X86_64_PLT32 cannot refer to absolute symbol: foo
+# CHECK: >>> defined in {{.*}}.script:1
+# CHECK: >>> referenced by {{.*}}.o:(.text+0x1)
+
+.text
+.globl _start
+_start:
+ call foo@PLT
diff --git a/test/ELF/linkerscript/symbol-memoryexpr.s b/test/ELF/linkerscript/symbol-memoryexpr.s
index cdd821dc585a..9214ba83ea51 100644
--- a/test/ELF/linkerscript/symbol-memoryexpr.s
+++ b/test/ELF/linkerscript/symbol-memoryexpr.s
@@ -13,7 +13,6 @@
# RUN: llvm-objdump -t %t1 | FileCheck %s
# CHECK: SYMBOL TABLE:
-# CHECK-NEXT: 0000000000000000 *UND* 00000000
# CHECK-NEXT: 0000000000008000 .text 00000000 _start
# CHECK-NEXT: 0000000000008000 *ABS* 00000000 origin
# CHECK-NEXT: 0000000000040000 *ABS* 00000000 length
diff --git a/test/ELF/linkerscript/target.s b/test/ELF/linkerscript/target.s
new file mode 100644
index 000000000000..32db5b7866c2
--- /dev/null
+++ b/test/ELF/linkerscript/target.s
@@ -0,0 +1,18 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: echo "TARGET(binary) INPUT(\"%t.o\") TARGET(elf64-x86-64) INPUT(\"%t.o\")" > %t.script
+# RUN: ld.lld --script %t.script -o %t.exe
+# RUN: llvm-readelf -symbols %t.exe | FileCheck %s
+
+# CHECK: _binary_
+# CHECK: foobar
+
+# RUN: echo "TARGET(foo)" > %t2.script
+# RUN: not ld.lld --script %t2.script -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s
+
+# ERR: unknown target: foo
+
+.global foobar
+foobar:
+ nop
diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s
index 6ddbf505ccbb..de494fa4975f 100644
--- a/test/ELF/linkerscript/unused-synthetic.s
+++ b/test/ELF/linkerscript/unused-synthetic.s
@@ -7,7 +7,7 @@
# RUN: }" > %t.script
# RUN: ld.lld -shared -o %t.so --script %t.script %t.o
-# RUN: llvm-readelf -s %t.so | FileCheck %s
+# RUN: llvm-readelf -S %t.so | FileCheck %s
# CHECK-NOT: .got
# CHECK-NOT: .plt
# CHECK: .dynsym
diff --git a/test/ELF/linkerscript/version-script.s b/test/ELF/linkerscript/version-script.s
index df666e1b39ea..67a0fd68ca7c 100644
--- a/test/ELF/linkerscript/version-script.s
+++ b/test/ELF/linkerscript/version-script.s
@@ -14,11 +14,11 @@
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: und@
+# CHECK-NEXT: Name: und
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 2
@@ -41,7 +41,7 @@
# UNDEF: Symbols [
# UNDEF-NEXT: Symbol {
# UNDEF-NEXT: Version: 0
-# UNDEF-NEXT: Name: @
+# UNDEF-NEXT: Name:
# UNDEF-NEXT: }
# UNDEF-NEXT: Symbol {
# UNDEF-NEXT: Version: 2
diff --git a/test/ELF/local-dynamic.s b/test/ELF/local-dynamic.s
index c122074fd7d9..0adad2bf41d9 100644
--- a/test/ELF/local-dynamic.s
+++ b/test/ELF/local-dynamic.s
@@ -65,7 +65,7 @@
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
@@ -74,7 +74,7 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: _start@
+// CHECK-NEXT: Name: _start
// CHECK-NEXT: Value:
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
diff --git a/test/ELF/local-ver-preemptible.s b/test/ELF/local-ver-preemptible.s
new file mode 100644
index 000000000000..80d78c4a8d86
--- /dev/null
+++ b/test/ELF/local-ver-preemptible.s
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: echo '.global foo; .type foo, @function; foo:' | \
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.so.o
+# RUN: ld.lld %t.so.o -o %t.so -shared
+
+# RUN: echo "{ global: main; local: *; };" > %t.script
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o %t.so -o %t -version-script %t.script
+# RUN: llvm-readelf -r --symbols %t | FileCheck %s
+
+# CHECK: Relocation section '.rela.plt' at offset {{.*}} contains 1 entries:
+# CHECK: R_X86_64_JUMP_SLOT 0000000000201020 foo + 0
+
+# CHECK: Symbol table '.dynsym' contains 2 entries:
+# CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name
+# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
+# CHECK-NEXT: 1: 0000000000201020 0 FUNC GLOBAL DEFAULT UND foo
+
+.globl _start
+_start:
+ movl $foo - ., %eax
diff --git a/test/ELF/lto-plugin-ignore.s b/test/ELF/lto-plugin-ignore.s
index 65230f1567e7..0370d458626b 100644
--- a/test/ELF/lto-plugin-ignore.s
+++ b/test/ELF/lto-plugin-ignore.s
@@ -6,5 +6,5 @@
# RUN: -plugin-opt=-data-sections -plugin-opt=thinlto -o /dev/null
# 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'
+# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-abc'
+# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-xyz'
diff --git a/test/ELF/lto/Inputs/libcall-archive.s b/test/ELF/lto/Inputs/libcall-archive.s
new file mode 100644
index 000000000000..6ca6e5fa821e
--- /dev/null
+++ b/test/ELF/lto/Inputs/libcall-archive.s
@@ -0,0 +1,2 @@
+.globl __sync_val_compare_and_swap_8
+__sync_val_compare_and_swap_8:
diff --git a/test/ELF/lto/amdgcn.ll b/test/ELF/lto/amdgcn.ll
new file mode 100644
index 000000000000..4281e209fd97
--- /dev/null
+++ b/test/ELF/lto/amdgcn.ll
@@ -0,0 +1,12 @@
+; REQUIRES: amdgpu
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t
+
+; Make sure the amdgcn triple is handled
+
+target triple = "amdgcn-amd-amdhsa"
+target datalayout = "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5"
+
+define void @_start() {
+ ret void
+}
diff --git a/test/ELF/lto/cache.ll b/test/ELF/lto/cache.ll
index 3f2bea9f2cdf..fe123989f22d 100644
--- a/test/ELF/lto/cache.ll
+++ b/test/ELF/lto/cache.ll
@@ -1,4 +1,6 @@
; REQUIRES: x86
+; NetBSD: noatime mounts currently inhibit 'touch' from updating atime
+; UNSUPPORTED: system-netbsd
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
@@ -13,12 +15,16 @@
; 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
; RUN: ls %t.cache | count 5
+; Increase the age of llvmcache-foo, which will give it the oldest time stamp
+; so that it is processed and removed first.
+; RUN: %python -c 'import os,sys,time; t=time.time()-120; os.utime(sys.argv[1],(t,t))' %t.cache/llvmcache-foo
+
; This should remove it.
; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k:prune_interval=0s -o %t3 %t2.o %t.o
; RUN: ls %t.cache | count 4
@@ -31,6 +37,20 @@
; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=1:prune_interval=0s -o %t3 %t2.o %t.o
; RUN: ls %t.cache | count 3
+; Check that we remove the least recently used file first.
+; RUN: rm -fr %t.cache
+; RUN: mkdir %t.cache
+; RUN: echo xyz > %t.cache/llvmcache-old
+; RUN: touch -t 198002011200 %t.cache/llvmcache-old
+; RUN: echo xyz > %t.cache/llvmcache-newer
+; RUN: touch -t 198002021200 %t.cache/llvmcache-newer
+; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=3:prune_interval=0s -o %t3 %t2.o %t.o
+; RUN: ls %t.cache | FileCheck %s
+
+; CHECK-NOT: llvmcache-old
+; CHECK: llvmcache-newer
+; CHECK-NOT: llvmcache-old
+
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/data-ordering-lto.s b/test/ELF/lto/data-ordering-lto.s
index bdacccc35400..f3cd52bd02b5 100644
--- a/test/ELF/lto/data-ordering-lto.s
+++ b/test/ELF/lto/data-ordering-lto.s
@@ -8,7 +8,7 @@
# 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-readelf -t %t2.out| FileCheck %s
+# RUN: llvm-readelf --symbols %t2.out| FileCheck %s
# Check that the order is tin -> dipsy -> pat.
diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll
index e5f0a4875f59..671f589da18d 100644
--- a/test/ELF/lto/defsym.ll
+++ b/test/ELF/lto/defsym.ll
@@ -3,14 +3,14 @@
; 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 -save-temps
-; RUN: llvm-readelf -t %t.so.lto.o | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-readelf --symbols %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 %t2.so -defsym=bar2=bar3 -save-temps
-; RUN: llvm-readelf -t %t2.so1.lto.o | FileCheck --check-prefix=OBJ %s
+; RUN: llvm-readelf --symbols %t2.so1.lto.o | FileCheck --check-prefix=OBJ %s
; RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=THIN
; OBJ: UND bar2
diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll
index c5473d833380..84b667b0eb0c 100644
--- a/test/ELF/lto/dynamic-list.ll
+++ b/test/ELF/lto/dynamic-list.ll
@@ -4,7 +4,7 @@
; RUN: ld.lld -o %t --dynamic-list %t.list -pie %t.o
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
-; CHECK: Name: foo@
+; CHECK: Name: foo
; CHECK-NEXT: Value: 0x1010
; CHECK-NEXT: Size: 1
; CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/lto/emit-llvm.ll b/test/ELF/lto/emit-llvm.ll
new file mode 100644
index 000000000000..bf38c982f02e
--- /dev/null
+++ b/test/ELF/lto/emit-llvm.ll
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+
+; RUN: opt -module-hash -module-summary %s -o %t.o
+; RUN: ld.lld --plugin-opt=emit-llvm -o %t.out.o %t.o
+; RUN: llvm-dis < %t.out.o -o - | FileCheck %s
+
+; CHECK: define internal void @main()
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @main() {
+ ret void
+}
diff --git a/test/ELF/lto/libcall-archive.ll b/test/ELF/lto/libcall-archive.ll
index 731e25938bd3..7e8ac183317d 100644
--- a/test/ELF/lto/libcall-archive.ll
+++ b/test/ELF/lto/libcall-archive.ll
@@ -1,10 +1,15 @@
+; REQUIRES: x86
; RUN: rm -f %t.a
; RUN: llvm-as -o %t.o %s
; RUN: llvm-as -o %t2.o %S/Inputs/libcall-archive.ll
-; RUN: llvm-ar rcs %t.a %t2.o
+; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t3.o %S/Inputs/libcall-archive.s
+; RUN: llvm-ar rcs %t.a %t2.o %t3.o
; RUN: ld.lld -o %t %t.o %t.a
; RUN: llvm-nm %t | FileCheck %s
+; RUN: ld.lld -o %t2 %t.o --start-lib %t2.o %t3.o --end-lib
+; RUN: llvm-nm %t2 | FileCheck %s
+; CHECK-NOT: T __sync_val_compare_and_swap_8
; CHECK: T _start
; CHECK: T memcpy
diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll
index a75000d5cfd3..23f15642682a 100644
--- a/test/ELF/lto/ltopasses-custom.ll
+++ b/test/ELF/lto/ltopasses-custom.ll
@@ -27,11 +27,11 @@ define void @barrier() {
; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \
; RUN: --lto-newpm-passes=iamnotapass -shared 2>&1 | \
; RUN: FileCheck %s --check-prefix=INVALID
-; INVALID: unable to parse pass pipeline description: iamnotapass
+; INVALID: unable to parse pass pipeline description 'iamnotapass': unknown pass name 'iamnotapass'
; Check that invalid AA pipelines are rejected gracefully.
; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2.so \
; RUN: --lto-newpm-passes=globaldce --lto-aa-pipeline=patatino \
; RUN: -shared 2>&1 | \
; RUN: FileCheck %s --check-prefix=INVALIDAA
-; INVALIDAA: unable to parse AA pipeline description: patatino
+; INVALIDAA: unknown alias analysis name 'patatino'
diff --git a/test/ELF/lto/opt-remarks.ll b/test/ELF/lto/opt-remarks.ll
index 19b141feb258..bef7e016a1c0 100644
--- a/test/ELF/lto/opt-remarks.ll
+++ b/test/ELF/lto/opt-remarks.ll
@@ -23,9 +23,10 @@
; YAML-NEXT: - Callee: tinkywinky
; YAML-NEXT: - String: ' inlined into '
; YAML-NEXT: - Caller: main
-; YAML-NEXT: - String: ' with cost='
+; YAML-NEXT: - String: ' with '
+; YAML-NEXT: - String: '(cost='
; YAML-NEXT: - Cost: '0'
-; YAML-NEXT: - String: ' (threshold='
+; YAML-NEXT: - String: ', threshold='
; YAML-NEXT: - Threshold: '337'
; YAML-NEXT: - String: ')'
; YAML-NEXT: ...
@@ -39,9 +40,10 @@
; YAML-HOT-NEXT: - Callee: tinkywinky
; YAML-HOT-NEXT: - String: ' inlined into '
; YAML-HOT-NEXT: - Caller: main
-; YAML-HOT-NEXT: - String: ' with cost='
+; YAML-HOT-NEXT: - String: ' with '
+; YAML-HOT-NEXT: - String: '(cost='
; YAML-HOT-NEXT: - Cost: '0'
-; YAML-HOT-NEXT: - String: ' (threshold='
+; YAML-HOT-NEXT: - String: ', threshold='
; YAML-HOT-NEXT: - Threshold: '337'
; YAML-HOT-NEXT: - String: ')'
; YAML-HOT-NEXT: ...
diff --git a/test/ELF/lto/ppc64le.ll b/test/ELF/lto/ppc64le.ll
new file mode 100644
index 000000000000..917b47231843
--- /dev/null
+++ b/test/ELF/lto/ppc64le.ll
@@ -0,0 +1,12 @@
+; REQUIRES: ppc
+
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t
+
+target datalayout = "e-m:e-i64:64-n32:64"
+target triple = "powerpc64le-unknown-linux-gnu"
+
+define void @__start() {
+ entry:
+ ret void
+}
diff --git a/test/ELF/lto/r600.ll b/test/ELF/lto/r600.ll
new file mode 100644
index 000000000000..1c95edcb4c56
--- /dev/null
+++ b/test/ELF/lto/r600.ll
@@ -0,0 +1,12 @@
+; REQUIRES: amdgpu
+; RUN: llvm-as %s -o %t.o
+; RUN: ld.lld %t.o -o %t
+
+; Make sure the r600 triple is handled
+
+target triple = "r600-mesa-mesa3d"
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5"
+
+define void @_start() {
+ ret void
+}
diff --git a/test/ELF/lto/relocatable.ll b/test/ELF/lto/relocatable.ll
index 2ec9144a37b0..5a0ed4252bfe 100644
--- a/test/ELF/lto/relocatable.ll
+++ b/test/ELF/lto/relocatable.ll
@@ -41,6 +41,15 @@
; CHECK-NEXT: Section: .text.foo
; CHECK-NEXT: }
; CHECK-NEXT: Symbol {
+; CHECK-NEXT: Name:
+; CHECK-NEXT: Value: 0x0
+; CHECK-NEXT: Size: 0
+; CHECK-NEXT: Binding: Local
+; CHECK-NEXT: Type: Section
+; CHECK-NEXT: Other: 0
+; CHECK-NEXT: Section: .llvm_addrsig
+; CHECK-NEXT: }
+; CHECK-NEXT: Symbol {
; CHECK-NEXT: Name: foo
; CHECK-NEXT: Value: 0x0
; CHECK-NEXT: Size: 1
diff --git a/test/ELF/lto/section-name.ll b/test/ELF/lto/section-name.ll
index 483184716a07..0ecc3778aef7 100644
--- a/test/ELF/lto/section-name.ll
+++ b/test/ELF/lto/section-name.ll
@@ -1,9 +1,9 @@
; REQUIRES: x86
; RUN: llvm-as %s -o %t.o
; RUN: ld.lld %t.o -o %t.so -shared
-; RUN: llvm-readelf -s %t.so | FileCheck %s
+; RUN: llvm-readelf -S %t.so | FileCheck %s
; RUN: ld.lld %t.o -o %t.so -shared --gc-sections
-; RUN: llvm-readelf -s %t.so | FileCheck --check-prefix=GC %s
+; RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=GC %s
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/shlib-undefined.ll b/test/ELF/lto/shlib-undefined.ll
index 6d37bfa6b304..eec40cc2771b 100644
--- a/test/ELF/lto/shlib-undefined.ll
+++ b/test/ELF/lto/shlib-undefined.ll
@@ -6,7 +6,7 @@
; RUN: ld.lld -o %t %t.o %t2.so
; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
-; CHECK: Name: __progname@
+; CHECK: Name: __progname
; CHECK-NEXT: Value: 0x201010
; CHECK-NEXT: Size: 1
; CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/lto/symbol-ordering-lto.s b/test/ELF/lto/symbol-ordering-lto.s
index 530b63c669a4..6a35c60772a6 100644
--- a/test/ELF/lto/symbol-ordering-lto.s
+++ b/test/ELF/lto/symbol-ordering-lto.s
@@ -8,7 +8,7 @@
# 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-readelf -t %t2.out| FileCheck %s
+# RUN: llvm-readelf --symbols %t2.out| FileCheck %s
# Check that the order is tin -> _start -> pat.
diff --git a/test/ELF/lto/thinlto-obj-path.ll b/test/ELF/lto/thinlto-obj-path.ll
index bb69bb876a28..2806d164a54c 100644
--- a/test/ELF/lto/thinlto-obj-path.ll
+++ b/test/ELF/lto/thinlto-obj-path.ll
@@ -7,7 +7,8 @@
; 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
+; RUN: llvm-nm %t4.o 2>&1 | FileCheck %s -check-prefix=NO-SYMBOLS
+; NO-SYMBOLS: no symbols
; CHECK: Format: ELF64-x86-64
diff --git a/test/ELF/lto/thinlto-object-suffix-replace.ll b/test/ELF/lto/thinlto-object-suffix-replace.ll
index 05ce942c70f8..c58a1f2ded0e 100644
--- a/test/ELF/lto/thinlto-object-suffix-replace.ll
+++ b/test/ELF/lto/thinlto-object-suffix-replace.ll
@@ -29,12 +29,12 @@
; 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
+; If filename does not end with old suffix, no suffix change should occur,
+; so ".thinlto.bc" will simply be appended to the input file name.
+; RUN: rm -f %t1.thinlink.bc.thinlto.bc
+; RUN: ld.lld --plugin-opt=thinlto-index-only \
+; RUN: --plugin-opt=thinlto-object-suffix-replace=".abc;.o" -shared %t1.thinlink.bc -o /dev/null
+; RUN: ls %t1.thinlink.bc.thinlto.bc
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/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll
index 6c3dc76be12a..f34abe68206c 100644
--- a/test/ELF/lto/undefined-puts.ll
+++ b/test/ELF/lto/undefined-puts.ll
@@ -25,4 +25,4 @@ declare i32 @printf(i8*, ...)
; CHECK: DynamicSymbols [
; CHECK: Symbol {
-; CHECK: Name: puts@
+; CHECK: Name: puts
diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll
index 35a36b5a8d78..eae5a35a6ff4 100644
--- a/test/ELF/lto/version-script.ll
+++ b/test/ELF/lto/version-script.ll
@@ -21,7 +21,7 @@ define void @bar() {
; DSO: DynamicSymbols [
; DSO: Symbol {
-; DSO: Name: @ (0)
+; DSO: Name:
; DSO: Value: 0x0
; DSO: Size: 0
; DSO: Binding: Local
diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll
index 4e82d4a0e8b0..997725fb8def 100644
--- a/test/ELF/lto/wrap-2.ll
+++ b/test/ELF/lto/wrap-2.ll
@@ -28,11 +28,15 @@
; THIN-NEXT: jmp{{.*}}<bar>
; Check that bar and __wrap_bar retain their original binding.
-; BIND: Name: __wrap_bar
+; BIND: Name: bar
; BIND-NEXT: Value:
; BIND-NEXT: Size:
; BIND-NEXT: Binding: Local
-; BIND: Name: bar
+; BIND: Name: __real_bar
+; BIND-NEXT: Value:
+; BIND-NEXT: Size:
+; BIND-NEXT: Binding: Local
+; BIND: Name: __wrap_bar
; BIND-NEXT: Value:
; BIND-NEXT: Size:
; BIND-NEXT: Binding: Local
diff --git a/test/ELF/map-file-i686.s b/test/ELF/map-file-i686.s
index bab2c4b377e2..5c8b15491151 100644
--- a/test/ELF/map-file-i686.s
+++ b/test/ELF/map-file-i686.s
@@ -7,15 +7,15 @@
_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)
+// CHECK: VMA LMA Size Align Out In Symbol
+// CHECK-NEXT: 401000 401000 1 4 .text
+// CHECK-NEXT: 401000 401000 1 4 {{.*}}{{/|\\}}map-file-i686.s.tmp1.o:(.text)
+// CHECK-NEXT: 401000 401000 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/merge-string-error.s b/test/ELF/merge-string-error.s
index 70a361b6ccde..a0ffaafde854 100644
--- a/test/ELF/merge-string-error.s
+++ b/test/ELF/merge-string-error.s
@@ -8,4 +8,4 @@
.data
.long .rodata.str1.1 + 4
-// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): entry is past the end of the section
+// CHECK: merge-string-error.s.tmp.o:(.rodata.str1.1): offset is outside the section
diff --git a/test/ELF/mergeable-errors.s b/test/ELF/mergeable-errors.s
new file mode 100644
index 000000000000..578589837f07
--- /dev/null
+++ b/test/ELF/mergeable-errors.s
@@ -0,0 +1,8 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t1 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.o:(.mergeable): string is not null terminated
+
+.section .mergeable,"MS",@progbits,2
+ .short 0x1122
diff --git a/test/ELF/mips-32.s b/test/ELF/mips-32.s
index 7efcfcd65167..85bc95592edb 100644
--- a/test/ELF/mips-32.s
+++ b/test/ELF/mips-32.s
@@ -41,8 +41,8 @@ v2:
# ^-- v2+4 ^-- v1
# SYM: SYMBOL TABLE:
-# SYM: 00020000 l .data 00000004 v1
-# SYM: 00020004 g .data 00000008 v2
+# SYM: 00020000 l O .data 00000004 v1
+# SYM: 00020004 g O .data 00000008 v2
# REL: Relocations [
# REL-NEXT: Section (7) .rel.dyn {
diff --git a/test/ELF/mips-64.s b/test/ELF/mips-64.s
index e37b75c070ec..70e445f5327a 100644
--- a/test/ELF/mips-64.s
+++ b/test/ELF/mips-64.s
@@ -25,8 +25,8 @@ v2:
# SYM: SYMBOL TABLE:
-# SYM: 00020000 l .data 00000004 v1
-# SYM: 00020008 g .data 00000008 v2
+# SYM: 00020000 l O .data 00000004 v1
+# SYM: 00020008 g O .data 00000008 v2
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s
index ebc2625970cb..2852b5088374 100644
--- a/test/ELF/mips-dynamic.s
+++ b/test/ELF/mips-dynamic.s
@@ -97,9 +97,9 @@
# DSO-NEXT: Size: 8
# DSO: ]
# DSO: DynamicSymbols [
-# DSO: Name: @
-# DSO: Name: __start@
-# DSO: Name: _foo@
+# DSO: Name:
+# DSO: Name: __start
+# DSO: Name: _foo
# DSO: ]
# DSO: DynamicSection [
# DSO-NEXT: Tag Type Name/Value
diff --git a/test/ELF/mips-dynsym-sort.s b/test/ELF/mips-dynsym-sort.s
index d1b935b63cff..3f98b7cd72e0 100644
--- a/test/ELF/mips-dynsym-sort.s
+++ b/test/ELF/mips-dynsym-sort.s
@@ -36,7 +36,7 @@ __start:
# the MIPS rules. v2 comes first as it is not in the GOT.
# v1 and v3 are sorted according to their order in the GOT.
# CHECK: DynamicSymbols [
-# CHECK: Name: v2@
-# CHECK: Name: v3@
-# CHECK: Name: v1@
+# CHECK: Name: v2
+# CHECK: Name: v3
+# CHECK: Name: v1
# CHECK: ]
diff --git a/test/ELF/mips-gnu-hash.s b/test/ELF/mips-gnu-hash.s
index e66bc893a076..fe4e95fee99b 100644
--- a/test/ELF/mips-gnu-hash.s
+++ b/test/ELF/mips-gnu-hash.s
@@ -7,7 +7,7 @@
# 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 /dev/null 2>&1 | FileCheck %s
-# CHECK: the .gnu.hash section is not compatible with the MIPS target.
+# CHECK: the .gnu.hash section is not compatible with the MIPS target
.globl __start
__start:
diff --git a/test/ELF/mips-got-and-copy.s b/test/ELF/mips-got-and-copy.s
index f4640bf30dfa..fed23d1eb762 100644
--- a/test/ELF/mips-got-and-copy.s
+++ b/test/ELF/mips-got-and-copy.s
@@ -32,7 +32,7 @@
# CHECK-NEXT: Value: 0x[[DATA0]]
# CHECK-NEXT: Type: Object
# CHECK-NEXT: Section: .bss
-# CHECK-NEXT: Name: data0@
+# CHECK-NEXT: Name: data0
# CHECK-NEXT: }
# CHECK-NEXT: Entry {
# CHECK-NEXT: Address:
@@ -41,7 +41,7 @@
# CHECK-NEXT: Value: 0x[[DATA1]]
# CHECK-NEXT: Type: Object
# CHECK-NEXT: Section: .bss
-# CHECK-NEXT: Name: data1@
+# CHECK-NEXT: Name: data1
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 0
diff --git a/test/ELF/mips-got-extsym.s b/test/ELF/mips-got-extsym.s
index ea57d77a0353..b5063a8559c9 100644
--- a/test/ELF/mips-got-extsym.s
+++ b/test/ELF/mips-got-extsym.s
@@ -43,7 +43,7 @@
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Type: None
# CHECK-NEXT: Section: Undefined
-# CHECK-NEXT: Name: _foo@
+# CHECK-NEXT: Name: _foo
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/mips-got-relocs.s b/test/ELF/mips-got-relocs.s
index d085df06524a..0465b08b9ed4 100644
--- a/test/ELF/mips-got-relocs.s
+++ b/test/ELF/mips-got-relocs.s
@@ -48,7 +48,7 @@ v1:
# EXE_SYM: SYMBOL TABLE:
# EXE_SYM: 00038000 .got 00000000 .hidden _gp
# ^-- .got + GP offset (0x7ff0)
-# EXE_SYM: 00030000 g .data 00000004 v1
+# EXE_SYM: 00030000 g O .data 00000004 v1
# EXE_GOT_BE: Contents of section .got:
@@ -72,7 +72,7 @@ v1:
# DSO_SYM: SYMBOL TABLE:
# DSO_SYM: 00028000 .got 00000000 .hidden _gp
# ^-- .got + GP offset (0x7ff0)
-# DSO_SYM: 00020000 g .data 00000004 v1
+# DSO_SYM: 00020000 g O .data 00000004 v1
# DSO_GOT_BE: Contents of section .got:
# DSO_GOT_BE: 20010 00000000 80000000 00020000
diff --git a/test/ELF/mips-got16-relocatable.s b/test/ELF/mips-got16-relocatable.s
index 04b7cbb8e904..e1100c2b31b3 100644
--- a/test/ELF/mips-got16-relocatable.s
+++ b/test/ELF/mips-got16-relocatable.s
@@ -14,9 +14,7 @@
# OBJ-NEXT: 00000000: R_MIPS_GOT16 .data
# OBJ-NEXT: 4: 27 24 00 00 addiu $4, $25, 0
# OBJ-NEXT: 00000004: R_MIPS_LO16 .data
-# OBJ-NEXT: 8: ef ef ef ef <unknown>
-# OBJ-NEXT: c: ef ef ef ef <unknown>
-# OBJ-NEXT: 10: 8f 99 00 00 lw $25, 0($gp)
+# OBJ: 10: 8f 99 00 00 lw $25, 0($gp)
# OBJ-NEXT: 00000010: R_MIPS_GOT16 .data
# OBJ-NEXT: 14: 27 24 00 10 addiu $4, $25, 16
# OBJ-NEXT: 00000014: R_MIPS_LO16 .data
@@ -25,9 +23,7 @@
# SO-NEXT: .text:
# SO-NEXT: 10000: 8f 99 80 18 lw $25, -32744($gp)
# SO-NEXT: 10004: 27 24 00 00 addiu $4, $25, 0
-# SO-NEXT: 10008: ef ef ef ef <unknown>
-# SO-NEXT: 1000c: ef ef ef ef <unknown>
-# SO-NEXT: 10010: 8f 99 80 18 lw $25, -32744($gp)
+# SO: 10010: 8f 99 80 18 lw $25, -32744($gp)
# SO-NEXT: 10014: 27 24 00 10 addiu $4, $25, 16
.text
diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s
index cf0847da53d3..53734ed31bb1 100644
--- a/test/ELF/mips-got16.s
+++ b/test/ELF/mips-got16.s
@@ -96,7 +96,7 @@
# GOT-NEXT: Value: 0x0
# GOT-NEXT: Type: None
# GOT-NEXT: Section: Undefined
-# GOT-NEXT: Name: foo@
+# GOT-NEXT: Name: foo
# GOT-NEXT: }
# GOT-NEXT: ]
# GOT-NEXT: Number of TLS and multi-GOT entries: 0
diff --git a/test/ELF/mips-hilo.s b/test/ELF/mips-hilo.s
index a00ffaa9fb1c..64f41140350b 100644
--- a/test/ELF/mips-hilo.s
+++ b/test/ELF/mips-hilo.s
@@ -47,6 +47,6 @@ g1:
# ^-- %lo(l1-4)
# CHECK: SYMBOL TABLE:
-# CHECK: 0030000 l .data 00000004 l1
-# CHECK: 0020000 .text 00000000 __start
-# CHECK: 0030004 g .data 00000004 g1
+# CHECK: 0030000 l O .data 00000004 l1
+# CHECK: 0020000 .text 00000000 __start
+# CHECK: 0030004 g O .data 00000004 g1
diff --git a/test/ELF/mips-mgot.s b/test/ELF/mips-mgot.s
index 0bb1a76ea8f5..4e364916c814 100644
--- a/test/ELF/mips-mgot.s
+++ b/test/ELF/mips-mgot.s
@@ -18,13 +18,13 @@
# 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
+# CHECK: 00000000 l O .tdata 00000000 loc0
+# CHECK: 00010000 .text 00000000 foo0
+# CHECK: 00000000 g O .tdata 00000000 tls0
+# CHECK: 00010020 .text 00000000 foo1
+# CHECK: 00000004 g O .tdata 00000000 tls1
+# CHECK: 00010030 .text 00000000 foo2
+# CHECK: 00000008 g O .tdata 00000000 tls2
# GOT: Relocations [
# GOT-NEXT: Section (7) .rel.dyn {
diff --git a/test/ELF/mips-micro-jal.s b/test/ELF/mips-micro-jal.s
index 18d41cf13cbc..f41d7dc3a6ce 100644
--- a/test/ELF/mips-micro-jal.s
+++ b/test/ELF/mips-micro-jal.s
@@ -57,9 +57,7 @@
# EB-NEXT: 20022: 45 f9 jalrs16 $25
# EB-NEXT: 20024: 0f 83 move $gp, $3
# EB-NEXT: 20026: 0c 00 nop
-# EB-NEXT: 20028: 00 00 00 00 nop
-# EB-NEXT: 2002c: 00 00 00 00 nop
-
+# EB-NEXT: ...
# EB-NEXT: 20030: 79 00 3f f7 addiupc $2, 65500
# EB-NEXT: 20034: ff 22 00 00 lw $25, 0($2)
# EB-NEXT: 20038: 45 99 jr16 $25
@@ -76,9 +74,7 @@
# EL-NEXT: 20022: f9 45 jalrs16 $25
# EL-NEXT: 20024: 83 0f move $gp, $3
# EL-NEXT: 20026: 00 0c nop
-# EL-NEXT: 20028: 00 00 00 00 nop
-# EL-NEXT: 2002c: 00 00 00 00 nop
-
+# EL-NEXT: ...
# EL-NEXT: 20030: 00 79 f7 3f addiupc $2, 65500
# EL-NEXT: 20034: 22 ff 00 00 lw $25, 0($2)
# EL-NEXT: 20038: 99 45 jr16 $25
@@ -127,9 +123,7 @@
# MIXED-NEXT: 20032: 45 f9 jalrs16 $25
# MIXED-NEXT: 20034: 0f 83 move $gp, $3
# MIXED-NEXT: 20036: 0c 00 nop
-# MIXED-NEXT: 20038: 00 00 00 00 nop
-# MIXED-NEXT: 2003c: 00 00 00 00 nop
-
+# MIXED-NEXT: ...
# MIXED-NEXT: 20040: 79 00 3f f3 addiupc $2, 65484
# MIXED-NEXT: 20044: ff 22 00 00 lw $25, 0($2)
# MIXED-NEXT: 20048: 45 99 jr16 $25
diff --git a/test/ELF/mips-micro-plt.s b/test/ELF/mips-micro-plt.s
index 6dcd6fbeec2d..24e90ae49a86 100644
--- a/test/ELF/mips-micro-plt.s
+++ b/test/ELF/mips-micro-plt.s
@@ -80,7 +80,7 @@
# CHECK-NEXT: Value: 0x20041
# CHECK-NEXT: Type: Function
# CHECK-NEXT: Section: Undefined
-# CHECK-NEXT: Name: foo0@
+# CHECK-NEXT: Name: foo0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: }
diff --git a/test/ELF/mips-npic-call-pic-os.s b/test/ELF/mips-npic-call-pic-os.s
index aea0fa1221dc..8799d832994d 100644
--- a/test/ELF/mips-npic-call-pic-os.s
+++ b/test/ELF/mips-npic-call-pic-os.s
@@ -19,37 +19,37 @@
# CHECK-NEXT: 20004: 08 00 80 08 j 131104 <foo1a>
# CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32
# CHECK-NEXT: 2000c: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_foo1b:
# CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 20014: 08 00 80 09 j 131108 <foo1b>
# CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36
# CHECK-NEXT: 2001c: 00 00 00 00 nop
+
# CHECK: foo1a:
# CHECK-NEXT: 20020: 00 00 00 00 nop
+
# CHECK: foo1b:
# CHECK-NEXT: 20024: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_foo2:
# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 2002c: 08 00 80 10 j 131136 <foo2>
# CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64
# CHECK-NEXT: 20034: 00 00 00 00 nop
-# CHECK-NEXT: 20038: ef ef ef ef <unknown>
-# CHECK-NEXT: 2003c: ef ef ef ef <unknown>
+
# CHECK: foo2:
# CHECK-NEXT: 20040: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_fpic:
# CHECK-NEXT: 20044: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 20048: 08 00 80 18 j 131168 <fpic>
# CHECK-NEXT: 2004c: 27 39 00 60 addiu $25, $25, 96
# CHECK-NEXT: 20050: 00 00 00 00 nop
-# CHECK-NEXT: 20054: ef ef ef ef <unknown>
-# CHECK-NEXT: 20058: ef ef ef ef <unknown>
-# CHECK-NEXT: 2005c: ef ef ef ef <unknown>
+
# CHECK: fpic:
# CHECK-NEXT: 20060: 00 00 00 00 nop
-# CHECK-NEXT: 20064: ef ef ef ef <unknown>
-# CHECK-NEXT: 20068: ef ef ef ef <unknown>
-# CHECK-NEXT: 2006c: ef ef ef ef <unknown>
+
# CHECK: fnpic:
# CHECK-NEXT: 20070: 00 00 00 00 nop
# CHECK-NEXT: Disassembly of section differentos:
@@ -79,40 +79,41 @@
# REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a>
# REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32
# REVERSE-NEXT: 2000c: 00 00 00 00 nop
+
# REVERSE: __LA25Thunk_foo1b:
# REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 20014: 08 00 80 09 j 131108 <foo1b>
# REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36
# REVERSE-NEXT: 2001c: 00 00 00 00 nop
+
# REVERSE: foo1a:
# REVERSE-NEXT: 20020: 00 00 00 00 nop
+
# REVERSE: foo1b:
# REVERSE-NEXT: 20024: 00 00 00 00 nop
+
# REVERSE: __LA25Thunk_foo2:
# REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 <foo2>
# REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64
# REVERSE-NEXT: 20034: 00 00 00 00 nop
-# REVERSE-NEXT: 20038: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2003c: ef ef ef ef <unknown>
+
# REVERSE: foo2:
# REVERSE-NEXT: 20040: 00 00 00 00 nop
-# REVERSE-NEXT: 20044: ef ef ef ef <unknown>
-# REVERSE-NEXT: 20048: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2004c: ef ef ef ef <unknown>
+
# REVERSE: __LA25Thunk_fpic:
# REVERSE-NEXT: 20050: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 20054: 08 00 80 18 j 131168 <fpic>
# REVERSE-NEXT: 20058: 27 39 00 60 addiu $25, $25, 96
# REVERSE-NEXT: 2005c: 00 00 00 00 nop
+
# REVERSE: fpic:
# REVERSE-NEXT: 20060: 00 00 00 00 nop
-# REVERSE-NEXT: 20064: ef ef ef ef <unknown>
-# REVERSE-NEXT: 20068: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2006c: ef ef ef ef <unknown>
+
# REVERSE: fnpic:
# REVERSE-NEXT: 20070: 00 00 00 00 nop
-# REVERSE-NEXT: Disassembly of section differentos:
+
+# REVERSE: Disassembly of section differentos:
# REVERSE-NEXT: __start:
# REVERSE-NEXT: 20074: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a>
# REVERSE-NEXT: 20078: 00 00 00 00 nop
diff --git a/test/ELF/mips-npic-call-pic-script.s b/test/ELF/mips-npic-call-pic-script.s
index 230704459463..11aa51aca83c 100644
--- a/test/ELF/mips-npic-call-pic-script.s
+++ b/test/ELF/mips-npic-call-pic-script.s
@@ -19,91 +19,28 @@
# CHECK-NEXT: 20004: 08 00 80 08 j 131104 <foo1a>
# CHECK-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32
# CHECK-NEXT: 2000c: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_foo1b:
# CHECK-NEXT: 20010: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 20014: 08 00 80 09 j 131108 <foo1b>
# CHECK-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36
# CHECK-NEXT: 2001c: 00 00 00 00 nop
+
# CHECK: foo1a:
# CHECK-NEXT: 20020: 00 00 00 00 nop
+
# CHECK: foo1b:
# CHECK-NEXT: 20024: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_foo2:
# CHECK-NEXT: 20028: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 2002c: 08 00 80 10 j 131136 <foo2>
# CHECK-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64
# CHECK-NEXT: 20034: 00 00 00 00 nop
-# CHECK-NEXT: 20038: ef ef ef ef <unknown>
-# CHECK-NEXT: 2003c: ef ef ef ef <unknown>
+
# CHECK: foo2:
# CHECK-NEXT: 20040: 00 00 00 00 nop
-# CHECK-NEXT: 20044: ef ef ef ef <unknown>
-# CHECK-NEXT: 20048: ef ef ef ef <unknown>
-# CHECK-NEXT: 2004c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20050: ef ef ef ef <unknown>
-# CHECK-NEXT: 20054: ef ef ef ef <unknown>
-# CHECK-NEXT: 20058: ef ef ef ef <unknown>
-# CHECK-NEXT: 2005c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20060: ef ef ef ef <unknown>
-# CHECK-NEXT: 20064: ef ef ef ef <unknown>
-# CHECK-NEXT: 20068: ef ef ef ef <unknown>
-# CHECK-NEXT: 2006c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20070: ef ef ef ef <unknown>
-# CHECK-NEXT: 20074: ef ef ef ef <unknown>
-# CHECK-NEXT: 20078: ef ef ef ef <unknown>
-# CHECK-NEXT: 2007c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20080: ef ef ef ef <unknown>
-# CHECK-NEXT: 20084: ef ef ef ef <unknown>
-# CHECK-NEXT: 20088: ef ef ef ef <unknown>
-# CHECK-NEXT: 2008c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20090: ef ef ef ef <unknown>
-# CHECK-NEXT: 20094: ef ef ef ef <unknown>
-# CHECK-NEXT: 20098: ef ef ef ef <unknown>
-# CHECK-NEXT: 2009c: ef ef ef ef <unknown>
-# CHECK-NEXT: 200a0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200a4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200a8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200ac: ef ef ef ef <unknown>
-# CHECK-NEXT: 200b0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200b4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200b8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200bc: ef ef ef ef <unknown>
-# CHECK-NEXT: 200c0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200c4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200c8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200cc: ef ef ef ef <unknown>
-# CHECK-NEXT: 200d0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200d4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200d8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200dc: ef ef ef ef <unknown>
-# CHECK-NEXT: 200e0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200e4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200e8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200ec: ef ef ef ef <unknown>
-# CHECK-NEXT: 200f0: ef ef ef ef <unknown>
-# CHECK-NEXT: 200f4: ef ef ef ef <unknown>
-# CHECK-NEXT: 200f8: ef ef ef ef <unknown>
-# CHECK-NEXT: 200fc: ef ef ef ef <unknown>
-# CHECK-NEXT: 20100: ef ef ef ef <unknown>
-# CHECK-NEXT: 20104: ef ef ef ef <unknown>
-# CHECK-NEXT: 20108: ef ef ef ef <unknown>
-# CHECK-NEXT: 2010c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20110: ef ef ef ef <unknown>
-# CHECK-NEXT: 20114: ef ef ef ef <unknown>
-# CHECK-NEXT: 20118: ef ef ef ef <unknown>
-# CHECK-NEXT: 2011c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20120: ef ef ef ef <unknown>
-# CHECK-NEXT: 20124: ef ef ef ef <unknown>
-# CHECK-NEXT: 20128: ef ef ef ef <unknown>
-# CHECK-NEXT: 2012c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20130: ef ef ef ef <unknown>
-# CHECK-NEXT: 20134: ef ef ef ef <unknown>
-# CHECK-NEXT: 20138: ef ef ef ef <unknown>
-# CHECK-NEXT: 2013c: ef ef ef ef <unknown>
-# CHECK-NEXT: 20140: ef ef ef ef <unknown>
-# CHECK-NEXT: 20144: ef ef ef ef <unknown>
-# CHECK-NEXT: 20148: ef ef ef ef <unknown>
-# CHECK-NEXT: 2014c: ef ef ef ef <unknown>
+
# CHECK: __start:
# CHECK-NEXT: 20150: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a>
# CHECK-NEXT: 20154: 00 00 00 00 nop
@@ -117,16 +54,16 @@
# CHECK-NEXT: 20174: 00 00 00 00 nop
# CHECK-NEXT: 20178: 0c 00 80 68 jal 131488 <fnpic>
# CHECK-NEXT: 2017c: 00 00 00 00 nop
+
# CHECK: __LA25Thunk_fpic:
# CHECK-NEXT: 20180: 3c 19 00 02 lui $25, 2
# CHECK-NEXT: 20184: 08 00 80 64 j 131472 <fpic>
# CHECK-NEXT: 20188: 27 39 01 90 addiu $25, $25, 400
# CHECK-NEXT: 2018c: 00 00 00 00 nop
+
# CHECK: fpic:
# CHECK-NEXT: 20190: 00 00 00 00 nop
-# CHECK-NEXT: 20194: ef ef ef ef <unknown>
-# CHECK-NEXT: 20198: ef ef ef ef <unknown>
-# CHECK-NEXT: 2019c: ef ef ef ef <unknown>
+
# CHECK: fnpic:
# CHECK-NEXT: 201a0: 00 00 00 00 nop
@@ -145,6 +82,7 @@ __start:
# RUN: echo "SECTIONS { .text 0x20000 : { *(.text) } }" > %t2.script
# RUN: ld.lld --script %t2.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t2.exe
# RUN: llvm-objdump -d %t2.exe | FileCheck -check-prefix=ORPH1 %s
+
# ORPH1: Disassembly of section .text:
# ORPH1-NEXT: __start:
# ORPH1-NEXT: 20000: 0c 00 80 15 jal 131156 <__LA25Thunk_foo1a>
@@ -159,42 +97,43 @@ __start:
# ORPH1-NEXT: 20024: 00 00 00 00 nop
# ORPH1-NEXT: 20028: 0c 00 80 14 jal 131152 <fnpic>
# ORPH1-NEXT: 2002c: 00 00 00 00 nop
+
# ORPH1: __LA25Thunk_fpic:
# ORPH1-NEXT: 20030: 3c 19 00 02 lui $25, 2
# ORPH1-NEXT: 20034: 08 00 80 10 j 131136 <fpic>
# ORPH1-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64
# ORPH1-NEXT: 2003c: 00 00 00 00 nop
+
# ORPH1: fpic:
# ORPH1-NEXT: 20040: 00 00 00 00 nop
-# ORPH1-NEXT: 20044: ef ef ef ef <unknown>
-# ORPH1-NEXT: 20048: ef ef ef ef <unknown>
-# ORPH1-NEXT: 2004c: ef ef ef ef <unknown>
+
# ORPH1: fnpic:
# ORPH1-NEXT: 20050: 00 00 00 00 nop
+
# ORPH1: __LA25Thunk_foo1a:
# ORPH1-NEXT: 20054: 3c 19 00 02 lui $25, 2
# ORPH1-NEXT: 20058: 08 00 80 20 j 131200 <foo1a>
# ORPH1-NEXT: 2005c: 27 39 00 80 addiu $25, $25, 128
# ORPH1-NEXT: 20060: 00 00 00 00 nop
+
# ORPH1: __LA25Thunk_foo1b:
# ORPH1-NEXT: 20064: 3c 19 00 02 lui $25, 2
# ORPH1-NEXT: 20068: 08 00 80 21 j 131204 <foo1b>
# ORPH1-NEXT: 2006c: 27 39 00 84 addiu $25, $25, 132
# ORPH1-NEXT: 20070: 00 00 00 00 nop
-# ORPH1-NEXT: 20074: ef ef ef ef <unknown>
-# ORPH1-NEXT: 20078: ef ef ef ef <unknown>
-# ORPH1-NEXT: 2007c: ef ef ef ef <unknown>
+
# ORPH1: foo1a:
# ORPH1-NEXT: 20080: 00 00 00 00 nop
+
# ORPH1: foo1b:
# ORPH1-NEXT: 20084: 00 00 00 00 nop
+
# ORPH1: __LA25Thunk_foo2:
# ORPH1-NEXT: 20088: 3c 19 00 02 lui $25, 2
# ORPH1-NEXT: 2008c: 08 00 80 28 j 131232 <foo2>
# ORPH1-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160
# ORPH1-NEXT: 20094: 00 00 00 00 nop
-# ORPH1-NEXT: 20098: ef ef ef ef <unknown>
-# ORPH1-NEXT: 2009c: ef ef ef ef <unknown>
+
# ORPH1: foo2:
# ORPH1-NEXT: 200a0: 00 00 00 00 nop
@@ -203,6 +142,7 @@ __start:
# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script
# RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe
# RUN: llvm-objdump -d %t3.exe | FileCheck -check-prefix=ORPH2 %s
+
# ORPH2: Disassembly of section .out:
# ORPH2-NEXT: __start:
# ORPH2-NEXT: 20000: 0c 00 80 18 jal 131168 <__LA25Thunk_foo1a>
@@ -217,39 +157,43 @@ __start:
# ORPH2-NEXT: 20024: 00 00 00 00 nop
# ORPH2-NEXT: 20028: 0c 00 80 14 jal 131152 <fnpic>
# ORPH2-NEXT: 2002c: 00 00 00 00 nop
+
# ORPH2: __LA25Thunk_fpic:
# ORPH2-NEXT: 20030: 3c 19 00 02 lui $25, 2
# ORPH2-NEXT: 20034: 08 00 80 10 j 131136 <fpic>
# ORPH2-NEXT: 20038: 27 39 00 40 addiu $25, $25, 64
# ORPH2-NEXT: 2003c: 00 00 00 00 nop
+
# ORPH2: fpic:
# ORPH2-NEXT: 20040: 00 00 00 00 nop
-# ORPH2-NEXT: 20044: ef ef ef ef <unknown>
-# ORPH2-NEXT: 20048: ef ef ef ef <unknown>
-# ORPH2-NEXT: 2004c: ef ef ef ef <unknown>
+
# ORPH2: fnpic:
# ORPH2-NEXT: 20050: 00 00 00 00 nop
# ORPH2-NEXT: Disassembly of section .text:
+
# ORPH2-NEXT: __LA25Thunk_foo1a:
# ORPH2-NEXT: 20060: 3c 19 00 02 lui $25, 2
# ORPH2-NEXT: 20064: 08 00 80 20 j 131200 <foo1a>
# ORPH2-NEXT: 20068: 27 39 00 80 addiu $25, $25, 128
# ORPH2-NEXT: 2006c: 00 00 00 00 nop
+
# ORPH2: __LA25Thunk_foo1b:
# ORPH2-NEXT: 20070: 3c 19 00 02 lui $25, 2
# ORPH2-NEXT: 20074: 08 00 80 21 j 131204 <foo1b>
# ORPH2-NEXT: 20078: 27 39 00 84 addiu $25, $25, 132
# ORPH2-NEXT: 2007c: 00 00 00 00 nop
+
# ORPH2: foo1a:
# ORPH2-NEXT: 20080: 00 00 00 00 nop
+
# ORPH2: foo1b:
# ORPH2-NEXT: 20084: 00 00 00 00 nop
+
# ORPH2: __LA25Thunk_foo2:
# ORPH2-NEXT: 20088: 3c 19 00 02 lui $25, 2
# ORPH2-NEXT: 2008c: 08 00 80 28 j 131232 <foo2>
# ORPH2-NEXT: 20090: 27 39 00 a0 addiu $25, $25, 160
# ORPH2-NEXT: 20094: 00 00 00 00 nop
-# ORPH2-NEXT: 20098: ef ef ef ef <unknown>
-# ORPH2-NEXT: 2009c: ef ef ef ef <unknown>
+
# ORPH2: foo2:
# ORPH2-NEXT: 200a0: 00 00 00 00 nop
diff --git a/test/ELF/mips-npic-call-pic.s b/test/ELF/mips-npic-call-pic.s
index c3c94d783410..5921c9f510fc 100644
--- a/test/ELF/mips-npic-call-pic.s
+++ b/test/ELF/mips-npic-call-pic.s
@@ -51,8 +51,6 @@
# CHECK-NEXT: 2005c: 08 00 80 1c j 131184 <foo2>
# CHECK-NEXT: 20060: 27 39 00 70 addiu $25, $25, 112
# CHECK-NEXT: 20064: 00 00 00 00 nop
-# CHECK-NEXT: 20068: ef ef ef ef <unknown>
-# CHECK-NEXT: 2006c: ef ef ef ef <unknown>
# CHECK: foo2:
# CHECK-NEXT: 20070: 00 00 00 00 nop
@@ -62,15 +60,9 @@
# CHECK-NEXT: 20078: 08 00 80 24 j 131216 <fpic>
# CHECK-NEXT: 2007c: 27 39 00 90 addiu $25, $25, 144
# CHECK-NEXT: 20080: 00 00 00 00 nop
-# CHECK-NEXT: 20084: ef ef ef ef <unknown>
-# CHECK-NEXT: 20088: ef ef ef ef <unknown>
-# CHECK-NEXT: 2008c: ef ef ef ef <unknown>
# CHECK: fpic:
# CHECK-NEXT: 20090: 00 00 00 00 nop
-# CHECK-NEXT: 20094: ef ef ef ef <unknown>
-# CHECK-NEXT: 20098: ef ef ef ef <unknown>
-# CHECK-NEXT: 2009c: ef ef ef ef <unknown>
# CHECK: fnpic:
# CHECK-NEXT: 200a0: 00 00 00 00 nop
@@ -87,27 +79,28 @@
# REVERSE-NEXT: 20004: 08 00 80 08 j 131104 <foo1a>
# REVERSE-NEXT: 20008: 27 39 00 20 addiu $25, $25, 32
# REVERSE-NEXT: 2000c: 00 00 00 00 nop
+
# REVERSE: __LA25Thunk_foo1b:
# REVERSE-NEXT: 20010: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 20014: 08 00 80 09 j 131108 <foo1b>
# REVERSE-NEXT: 20018: 27 39 00 24 addiu $25, $25, 36
# REVERSE-NEXT: 2001c: 00 00 00 00 nop
+
# REVERSE: foo1a:
# REVERSE-NEXT: 20020: 00 00 00 00 nop
+
# REVERSE: foo1b:
# REVERSE-NEXT: 20024: 00 00 00 00 nop
+
# REVERSE: __LA25Thunk_foo2:
# REVERSE-NEXT: 20028: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 2002c: 08 00 80 10 j 131136 <foo2>
# REVERSE-NEXT: 20030: 27 39 00 40 addiu $25, $25, 64
# REVERSE-NEXT: 20034: 00 00 00 00 nop
-# REVERSE-NEXT: 20038: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2003c: ef ef ef ef <unknown>
+
# REVERSE: foo2:
# REVERSE-NEXT: 20040: 00 00 00 00 nop
-# REVERSE-NEXT: 20044: ef ef ef ef <unknown>
-# REVERSE-NEXT: 20048: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2004c: ef ef ef ef <unknown>
+
# REVERSE: __start:
# REVERSE-NEXT: 20050: 0c 00 80 00 jal 131072 <__LA25Thunk_foo1a>
# REVERSE-NEXT: 20054: 00 00 00 00 nop
@@ -121,16 +114,16 @@
# REVERSE-NEXT: 20074: 00 00 00 00 nop
# REVERSE-NEXT: 20078: 0c 00 80 28 jal 131232 <fnpic>
# REVERSE-NEXT: 2007c: 00 00 00 00 nop
+
# REVERSE: __LA25Thunk_fpic:
# REVERSE-NEXT: 20080: 3c 19 00 02 lui $25, 2
# REVERSE-NEXT: 20084: 08 00 80 24 j 131216 <fpic>
# REVERSE-NEXT: 20088: 27 39 00 90 addiu $25, $25, 144
# REVERSE-NEXT: 2008c: 00 00 00 00 nop
+
# REVERSE: fpic:
# REVERSE-NEXT: 20090: 00 00 00 00 nop
-# REVERSE-NEXT: 20094: ef ef ef ef <unknown>
-# REVERSE-NEXT: 20098: ef ef ef ef <unknown>
-# REVERSE-NEXT: 2009c: ef ef ef ef <unknown>
+
# REVERSE: fnpic:
# REVERSE-NEXT: 200a0: 00 00 00 00 nop
diff --git a/test/ELF/mips-sto-plt.s b/test/ELF/mips-sto-plt.s
index b4d3ee391414..4bd0d9e7ba44 100644
--- a/test/ELF/mips-sto-plt.s
+++ b/test/ELF/mips-sto-plt.s
@@ -9,7 +9,7 @@
# RUN: llvm-readobj -dt -mips-plt-got %t.exe | FileCheck %s
# CHECK: Symbol {
-# CHECK: Name: foo0@
+# CHECK: Name: foo0
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
@@ -18,7 +18,7 @@
# CHECK-NEXT: Section: Undefined
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo1@
+# CHECK-NEXT: Name: foo1
# CHECK-NEXT: Value: 0x[[FOO1:[0-9A-F]+]]
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global
diff --git a/test/ELF/mips-tls-64.s b/test/ELF/mips-tls-64.s
index f000755b4e82..2d0749edc585 100644
--- a/test/ELF/mips-tls-64.s
+++ b/test/ELF/mips-tls-64.s
@@ -28,9 +28,9 @@
# 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
+# DIS: 0000000000000000 l O .tdata 00000000 loc
+# DIS: 0000000000000004 g O .tdata 00000000 bar
+# DIS: 0000000000000000 g O *UND* 00000000 foo
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
diff --git a/test/ELF/mips-tls-hilo.s b/test/ELF/mips-tls-hilo.s
index ae54602327a9..6b6df17eb97d 100644
--- a/test/ELF/mips-tls-hilo.s
+++ b/test/ELF/mips-tls-hilo.s
@@ -20,7 +20,7 @@
# DIS-NEXT: 2000c: 24 62 90 00 addiu $2, $3, -28672
# %lo(loc0 - .tdata - 0x7000) --^
-# DIS: 00000000 l .tdata 00000000 loc0
+# DIS: 00000000 l O .tdata 00000000 loc0
# CHECK: Relocations [
# CHECK-NEXT: ]
diff --git a/test/ELF/mips-tls-static-64.s b/test/ELF/mips-tls-static-64.s
index 04f18fa57585..23c775fb32f5 100644
--- a/test/ELF/mips-tls-static-64.s
+++ b/test/ELF/mips-tls-static-64.s
@@ -11,8 +11,8 @@
# CHECK-NEXT: 30010 ffff9004
#
# CHECK: SYMBOL TABLE:
-# CHECK: 0000000000020004 .text 00000000 __tls_get_addr
-# CHECK: 0000000000000000 g .tdata 00000000 tls1
+# CHECK: 0000000000020004 .text 00000000 __tls_get_addr
+# CHECK: 0000000000000000 g O .tdata 00000000 tls1
.text
.global __start
diff --git a/test/ELF/mips-tls-static.s b/test/ELF/mips-tls-static.s
index b09f5516bc89..9a1294003f48 100644
--- a/test/ELF/mips-tls-static.s
+++ b/test/ELF/mips-tls-static.s
@@ -13,8 +13,8 @@
# CHECK-NEXT: 30020 ffff8000 00000001 00000000
#
# CHECK: SYMBOL TABLE:
-# CHECK: 0002000c .text 00000000 __tls_get_addr
-# CHECK: 00000000 g .tdata 00000000 tls1
+# CHECK: 0002000c .text 00000000 __tls_get_addr
+# CHECK: 00000000 g O .tdata 00000000 tls1
.text
.global __start
diff --git a/test/ELF/mips-tls.s b/test/ELF/mips-tls.s
index ece55c69b303..5e1f8a957d20 100644
--- a/test/ELF/mips-tls.s
+++ b/test/ELF/mips-tls.s
@@ -26,9 +26,9 @@
# DIS-NEXT: 30020 00000000 00000000 00000001 00000000
# DIS-NEXT: 30030 00000001 ffff8004
-# DIS: 00000000 l .tdata 00000000 loc
-# DIS: 00000004 g .tdata 00000000 bar
-# DIS: 00000000 g *UND* 00000000 foo
+# DIS: 00000000 l O .tdata 00000000 loc
+# DIS: 00000004 g O .tdata 00000000 bar
+# DIS: 00000000 g O *UND* 00000000 foo
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
diff --git a/test/ELF/mips-traps.s b/test/ELF/mips-traps.s
new file mode 100644
index 000000000000..783d1f298374
--- /dev/null
+++ b/test/ELF/mips-traps.s
@@ -0,0 +1,22 @@
+# Check trap instruction encoding.
+
+# REQUIRES: mips
+
+# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mcpu=mips32r6 -o %t.o %s
+# RUN: ld.lld -r -o %t %t.o %t.o
+# RUN: llvm-objdump -d -r %t | FileCheck --check-prefix=EB %s
+
+# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux -mcpu=mips32r6 -o %t.o %s
+# RUN: ld.lld -r -o %t %t.o %t.o
+# RUN: llvm-objdump -d -r %t | FileCheck --check-prefix=EL %s
+
+# EB: 8: 04 17 00 01 sigrie 1
+# EL: 8: 01 00 17 04 sigrie 1
+
+ .text
+ lw $t9, %got(.data)($gp)
+ addiu $a0, $t9, %lo(.data)
+
+ .data
+data:
+ .word 0
diff --git a/test/ELF/msp430.s b/test/ELF/msp430.s
new file mode 100644
index 000000000000..96820acbc3f9
--- /dev/null
+++ b/test/ELF/msp430.s
@@ -0,0 +1,43 @@
+; REQUIRES: msp430
+; RUN: llvm-mc -filetype=obj -triple=msp430-elf -o %t1.o %s
+; RUN: echo -e '.global _start\n _start: nop' | llvm-mc -filetype=obj -triple=msp430-elf -o %t2.o -
+; RUN: ld.lld -o %t.exe --Tdata=0x2000 --Ttext=0x8000 --defsym=_byte=0x21 %t2.o %t1.o
+; RUN: llvm-objdump -s -d %t.exe | FileCheck %s
+
+;; Check handling of basic msp430 relocation types.
+
+ .text
+ .global foo
+foo:
+;; R_MSP430_10_PCREL
+ jmp _start
+
+; CHECK: Disassembly of section .text:
+; CHECK-NEXT: _start:
+; CHECK-NEXT: 8000: {{.*}} nop
+; CHECK: foo:
+; CHECK-NEXT: 8004: {{.*}} jmp $-4
+
+;; R_MSP430_16_BYTE
+ call #_start
+
+; CHECK: call #32768
+
+;; R_MSP430_16_PCREL_BYTE
+ mov #-1, _start
+
+; CHECK: 800a: {{.*}} mov #-1, -12
+
+ .data
+;; R_MSP430_8
+ .byte _byte
+;; R_MSP430_16
+ .word _start
+;; R_MSP430_32
+ .long _start
+
+; CHECK: Contents of section .data:
+; CHECK-NEXT: 2000 21008000 800000
+
+; RUN: od -x %t.exe | FileCheck -check-prefix=TRAP %s
+; TRAP: 4343 4343 4343 4343 4343 4343 4343 4343
diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s
index 1a4bf98c181e..4e8bcee2a1a0 100644
--- a/test/ELF/no-obj.s
+++ b/test/ELF/no-obj.s
@@ -1,5 +1,6 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: rm -f %t.a
// RUN: llvm-ar rcs %t.a %t.o
// RUN: not ld.lld -o /dev/null -u _start %t.a 2>&1 | FileCheck %s
diff --git a/test/ELF/note-first-page.s b/test/ELF/note-first-page.s
new file mode 100644
index 000000000000..a259344a1e5b
--- /dev/null
+++ b/test/ELF/note-first-page.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 --build-id=md5 --shared -o %t.so
+# RUN: llvm-readelf -S %t.so | FileCheck %s
+
+# Check .note.gnu.build-id is placed before other potentially large sections
+# (.dynsym .dynstr (and .rela.dyn in PIE)). This ensures the note information
+# available in core files because various core dumpers ensure the first page is
+# available.
+
+# CHECK: [ 1] .note.gnu.build-id
+# CHECK: [ 2] .dynsym
diff --git a/test/ELF/oformat-binary.s b/test/ELF/oformat-binary.s
index e68f07c57732..22a25f04c64d 100644
--- a/test/ELF/oformat-binary.s
+++ b/test/ELF/oformat-binary.s
@@ -20,6 +20,7 @@
# ERR: unknown --oformat value: foo
# RUN: ld.lld -o /dev/null %t --oformat elf
+# RUN: ld.lld -o /dev/null %t --oformat elf-foo
.text
.align 4
diff --git a/test/ELF/pack-dyn-relocs-loop.s b/test/ELF/pack-dyn-relocs-loop.s
new file mode 100644
index 000000000000..308ead5cf5f2
--- /dev/null
+++ b/test/ELF/pack-dyn-relocs-loop.s
@@ -0,0 +1,66 @@
+// REQUIRES: arm, aarch64
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-android %s -o %t.o
+// RUN: ld.lld -shared %t.o -o %t.so --pack-dyn-relocs=android
+// RUN: llvm-readobj -s %t.so | FileCheck %s
+
+// This test is making sure the Android packed relocation support doesn't
+// cause an infinite loop due to the size of the section oscillating
+// (because the size of the section impacts the layout of the following
+// sections).
+
+// This test is very sensitive to the exact section sizes and offsets,
+// so check that they don't change.
+// CHECK: Name: .rela.dyn (33)
+// CHECK-NEXT: Type: SHT_ANDROID_RELA (0x60000002)
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x210
+// CHECK-NEXT: Offset: 0x210
+// CHECK-NEXT: Size: 21
+
+// CHECK: Name: x (43)
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x225
+// CHECK-NEXT: Offset: 0x225
+// CHECK-NEXT: Size: 64980
+
+// CHECK: Name: barr (45)
+// CHECK-NEXT: Type: SHT_PROGBITS (0x1)
+// CHECK-NEXT: Flags [ (0x2)
+// CHECK-NEXT: SHF_ALLOC (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0xFFFA
+// CHECK-NEXT: Offset: 0xFFFA
+// CHECK-NEXT: Size: 0
+
+// CHECK: Name: foo (62)
+// 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: 0x10004
+// CHECK-NEXT: Offset: 0x10004
+// CHECK-NEXT: Size: 12
+
+
+.data
+.long 0
+
+.section foo,"aw"
+foof:
+.long foof
+.long bar-53
+.long bar
+
+.section x,"a"
+.zero 64980
+
+.section barr,"a"
+.p2align 1
+bar:
diff --git a/test/ELF/pack-dyn-relocs-tls-aarch64.s b/test/ELF/pack-dyn-relocs-tls-aarch64.s
new file mode 100644
index 000000000000..978e2e7b2426
--- /dev/null
+++ b/test/ELF/pack-dyn-relocs-tls-aarch64.s
@@ -0,0 +1,34 @@
+// REQUIRES: aarch64
+
+// RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o
+// RUN: ld.lld -shared --pack-dyn-relocs=android %t.o -o %t.so
+// RUN: llvm-readobj -relocations %t.so | FileCheck %s
+
+// Bug 37841: Symbol::getVA must work on TLS symbols during the layout loop in
+// finalizeSections.
+
+ .global foo
+foo:
+ adrp x0, :tlsdesc:tlsvar1
+ ldr x1, [x0, :tlsdesc_lo12:tlsvar1]
+ add x0, x0, :tlsdesc_lo12:tlsvar1
+ .tlsdesccall tlsvar1
+
+// Also test an atypical IE access from a shared object to a local TLS symbol.
+
+ .global bar
+bar:
+ adrp x0, :gottprel:tlsvar2
+ ldr x0, [x0, #:gottprel_lo12:tlsvar2]
+
+ .section .tdata,"awT",@progbits
+ .space 0x1234
+tlsvar1:
+ .word 42
+tlsvar2:
+ .word 17
+
+// CHECK: Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT: R_AARCH64_TLSDESC - 0x1234
+// CHECK-NEXT: R_AARCH64_TLS_TPREL64 - 0x1238
+// CHECK-NEXT: }
diff --git a/test/ELF/pack-dyn-relocs-tls-x86-64.s b/test/ELF/pack-dyn-relocs-tls-x86-64.s
new file mode 100644
index 000000000000..491efa6cc1d4
--- /dev/null
+++ b/test/ELF/pack-dyn-relocs-tls-x86-64.s
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -shared --pack-dyn-relocs=android %t.o -o %t.so
+// RUN: llvm-readobj -relocations %t.so | FileCheck %s
+
+// Bug 37841: Symbol::getVA must work on TLS symbols during the layout loop in
+// finalizeSections. This test uses an atypical IE access in a shared object to
+// access a local TLS symbol, because a more typical access would avoid the
+// bug.
+
+ .globl foo
+foo:
+ movq tlsvar@GOTTPOFF(%rip), %rcx
+
+ .section .tdata,"awT",@progbits
+ .space 0x1234
+tlsvar:
+ .word 42
+
+// CHECK: Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT: R_X86_64_TPOFF64 - 0x1234
+// CHECK-NEXT: }
diff --git a/test/ELF/plt-aarch64.s b/test/ELF/plt-aarch64.s
index 8f637bf593f4..f9c53a46f3eb 100644
--- a/test/ELF/plt-aarch64.s
+++ b/test/ELF/plt-aarch64.s
@@ -85,6 +85,8 @@
// foo@plt
// Page(0x30018) - Page(0x10030) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-EMPTY:
+// DISASMDSO-NEXT: foo@plt:
// DISASMDSO-NEXT: 10030: 90 00 00 90 adrp x16, #65536
// 0x3018 & 0xFFF = 0x18 = 24
// DISASMDSO-NEXT: 10034: 11 0e 40 f9 ldr x17, [x16, #24]
@@ -93,6 +95,8 @@
// bar@plt
// Page(0x30020) - Page(0x10040) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-EMPTY:
+// DISASMDSO-NEXT: bar@plt:
// DISASMDSO-NEXT: 10040: 90 00 00 90 adrp x16, #65536
// 0x3020 & 0xFFF = 0x20 = 32
// DISASMDSO-NEXT: 10044: 11 12 40 f9 ldr x17, [x16, #32]
@@ -101,6 +105,8 @@
// weak@plt
// Page(0x30028) - Page(0x10050) = 0x20000 - 0x10000 = 0x10000 = 65536
+// DISASMDSO-EMPTY:
+// DISASMDSO-NEXT: weak@plt:
// DISASMDSO-NEXT: 10050: 90 00 00 90 adrp x16, #65536
// 0x3028 & 0xFFF = 0x28 = 40
// DISASMDSO-NEXT: 10054: 11 16 40 f9 ldr x17, [x16, #40]
@@ -113,7 +119,7 @@
// CHECKEXE-NEXT: SHF_ALLOC
// CHECKEXE-NEXT: SHF_EXECINSTR
// CHECKEXE-NEXT: ]
-// CHECKEXE-NEXT: Address: 0x20010
+// CHECKEXE-NEXT: Address: 0x210010
// CHECKEXE-NEXT: Offset:
// CHECKEXE-NEXT: Size: 64
// CHECKEXE-NEXT: Link:
@@ -126,7 +132,7 @@
// CHECKEXE-NEXT: SHF_ALLOC
// CHECKEXE-NEXT: SHF_WRITE
// CHECKEXE-NEXT: ]
-// CHECKEXE-NEXT: Address: 0x30000
+// CHECKEXE-NEXT: Address: 0x220000
// CHECKEXE-NEXT: Offset:
// CHECKEXE-NEXT: Size: 40
// CHECKEXE-NEXT: Link:
@@ -136,59 +142,63 @@
// CHECKEXE: Relocations [
// CHECKEXE-NEXT: Section ({{.*}}) .rela.plt {
-// &(.got.plt[3]) = 0x30000 + 3 * 8 = 0x30018
-// CHECKEXE-NEXT: 0x30018 R_AARCH64_JUMP_SLOT bar 0x0
+// &(.got.plt[3]) = 0x220000 + 3 * 8 = 0x220018
+// CHECKEXE-NEXT: 0x220018 R_AARCH64_JUMP_SLOT bar 0x0
-// &(.got.plt[4]) = 0x30000 + 4 * 8 = 0x30020
-// CHECKEXE-NEXT: 0x30020 R_AARCH64_JUMP_SLOT weak 0x0
+// &(.got.plt[4]) = 0x220000 + 4 * 8 = 0x220020
+// CHECKEXE-NEXT: 0x220020 R_AARCH64_JUMP_SLOT weak 0x0
// CHECKEXE-NEXT: }
// CHECKEXE-NEXT: ]
// DUMPEXE: Contents of section .got.plt:
// .got.plt[0..2] = 0 (reserved)
// .got.plt[3..4] = .plt = 0x40010
-// DUMPEXE-NEXT: 30000 00000000 00000000 00000000 00000000 ................
-// DUMPEXE-NEXT: 30010 00000000 00000000 10000200 00000000 ................
-// DUMPEXE-NEXT: 30020 10000200 00000000 ........
+// DUMPEXE-NEXT: 220000 00000000 00000000 00000000 00000000
+// DUMPEXE-NEXT: 220010 00000000 00000000 10002100 00000000
+// DUMPEXE-NEXT: 220020 10002100 00000000
// DISASMEXE: _start:
-// 0x2000c - 0x20000 = 0xc = 12
-// DISASMEXE-NEXT: 20000: 03 00 00 14 b #12
-// 0x20030 - 0x20004 = 0x2c = 44
-// DISASMEXE-NEXT: 20004: 0b 00 00 14 b #44
-// 0x20040 - 0x20008 = 0x38 = 56
-// DISASMEXE-NEXT: 20008: 0e 00 00 14 b #56
+// 0x21000c - 0x210000 = 0xc = 12
+// DISASMEXE-NEXT: 210000: 03 00 00 14 b #12
+// 0x210030 - 0x210004 = 0x2c = 44
+// DISASMEXE-NEXT: 210004: 0b 00 00 14 b #44
+// 0x210040 - 0x210008 = 0x38 = 56
+// DISASMEXE-NEXT: 210008: 0e 00 00 14 b #56
// DISASMEXE: foo:
-// DISASMEXE-NEXT: 2000c: 1f 20 03 d5 nop
+// DISASMEXE-NEXT: 21000c: 1f 20 03 d5 nop
// DISASMEXE: Disassembly of section .plt:
// DISASMEXE-NEXT: .plt:
-// DISASMEXE-NEXT: 20010: f0 7b bf a9 stp x16, x30, [sp, #-16]!
-// &(.got.plt[2]) = 0x300B0 + 2 * 8 = 0x300C0
-// Page(0x30010) - Page(0x20014) = 0x30000 - 0x20000 = 0x10000 = 65536
-// DISASMEXE-NEXT: 20014: 90 00 00 90 adrp x16, #65536
+// DISASMEXE-NEXT: 210010: f0 7b bf a9 stp x16, x30, [sp, #-16]!
+// &(.got.plt[2]) = 0x2200B0 + 2 * 8 = 0x2200C0
+// Page(0x220010) - Page(0x210014) = 0x220000 - 0x210000 = 0x10000 = 65536
+// DISASMEXE-NEXT: 210014: 90 00 00 90 adrp x16, #65536
// 0x120c0 & 0xFFF = 0xC0 = 192
-// DISASMEXE-NEXT: 20018: 11 0a 40 f9 ldr x17, [x16, #16]
-// DISASMEXE-NEXT: 2001c: 10 42 00 91 add x16, x16, #16
-// DISASMEXE-NEXT: 20020: 20 02 1f d6 br x17
-// DISASMEXE-NEXT: 20024: 1f 20 03 d5 nop
-// DISASMEXE-NEXT: 20028: 1f 20 03 d5 nop
-// DISASMEXE-NEXT: 2002c: 1f 20 03 d5 nop
+// DISASMEXE-NEXT: 210018: 11 0a 40 f9 ldr x17, [x16, #16]
+// DISASMEXE-NEXT: 21001c: 10 42 00 91 add x16, x16, #16
+// DISASMEXE-NEXT: 210020: 20 02 1f d6 br x17
+// DISASMEXE-NEXT: 210024: 1f 20 03 d5 nop
+// DISASMEXE-NEXT: 210028: 1f 20 03 d5 nop
+// DISASMEXE-NEXT: 21002c: 1f 20 03 d5 nop
// bar@plt
-// Page(0x40018) - Page(0x20030) = 0x30000 - 0x20000 = 0x10000 = 65536
-// DISASMEXE-NEXT: 20030: 90 00 00 90 adrp x16, #65536
-// DISASMEXE-NEXT: 20034: 11 0e 40 f9 ldr x17, [x16, #24]
-// DISASMEXE-NEXT: 20038: 10 62 00 91 add x16, x16, #24
-// DISASMEXE-NEXT: 2003c: 20 02 1f d6 br x17
+// Page(0x40018) - Page(0x210030) = 0x220000 - 0x210000 = 0x10000 = 65536
+// DISASMEXE-EMPTY:
+// DISASMEXE-NEXT: bar@plt:
+// DISASMEXE-NEXT: 210030: 90 00 00 90 adrp x16, #65536
+// DISASMEXE-NEXT: 210034: 11 0e 40 f9 ldr x17, [x16, #24]
+// DISASMEXE-NEXT: 210038: 10 62 00 91 add x16, x16, #24
+// DISASMEXE-NEXT: 21003c: 20 02 1f d6 br x17
// weak@plt
-// Page(0x40020) - Page(0x20040) = 0x30000 - 0x20000 = 0x10000 = 65536
-// DISASMEXE-NEXT: 20040: 90 00 00 90 adrp x16, #65536
-// DISASMEXE-NEXT: 20044: 11 12 40 f9 ldr x17, [x16, #32]
-// DISASMEXE-NEXT: 20048: 10 82 00 91 add x16, x16, #32
-// DISASMEXE-NEXT: 2004c: 20 02 1f d6 br x17
+// Page(0x40020) - Page(0x210040) = 0x220000 - 0x210000 = 0x10000 = 65536
+// DISASMEXE-EMPTY:
+// DISASMEXE-NEXT: weak@plt:
+// DISASMEXE-NEXT: 210040: 90 00 00 90 adrp x16, #65536
+// DISASMEXE-NEXT: 210044: 11 12 40 f9 ldr x17, [x16, #32]
+// DISASMEXE-NEXT: 210048: 10 82 00 91 add x16, x16, #32
+// DISASMEXE-NEXT: 21004c: 20 02 1f d6 br x17
.global _start,foo,bar
.weak weak
diff --git a/test/ELF/plt-i686.s b/test/ELF/plt-i686.s
index c24cab20e769..8a5863310eae 100644
--- a/test/ELF/plt-i686.s
+++ b/test/ELF/plt-i686.s
@@ -17,7 +17,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_EXECINSTR
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x11020
+// CHECK-NEXT: Address: 0x401020
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 48
// CHECK-NEXT: Link: 0
@@ -30,7 +30,7 @@
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x12000
+// CHECK-NEXT: Address: 0x402000
// CHECK-NEXT: Offset: 0x2000
// CHECK-NEXT: Size: 20
// CHECK-NEXT: Link: 0
@@ -42,8 +42,8 @@
// 0x12000 + got.plt.reserved(12) + 4 = 0x12010
// CHECK: Relocations [
// CHECK-NEXT: Section ({{.*}}) .rel.plt {
-// CHECK-NEXT: 0x1200C R_386_JUMP_SLOT bar 0x0
-// CHECK-NEXT: 0x12010 R_386_JUMP_SLOT zed 0x0
+// CHECK-NEXT: 0x40200C R_386_JUMP_SLOT bar 0x0
+// CHECK-NEXT: 0x402010 R_386_JUMP_SLOT zed 0x0
// CHECK-NEXT: }
// CHECK-NEXT: ]
@@ -51,40 +51,44 @@
// values:
// 16 is the size of PLT[0]
-// (0x11010 + 16) - (0x11000 + 1) - 4 = 27
-// (0x11010 + 16) - (0x11005 + 1) - 4 = 22
-// (0x11020 + 16) - (0x1100a + 1) - 4 = 33
+// (0x401010 + 16) - (0x401000 + 1) - 4 = 27
+// (0x401010 + 16) - (0x401005 + 1) - 4 = 22
+// (0x401020 + 16) - (0x40100a + 1) - 4 = 33
// DISASM: local:
-// DISASM-NEXT: 11000: {{.*}}
-// DISASM-NEXT: 11002: {{.*}}
+// DISASM-NEXT: 401000: {{.*}}
+// DISASM-NEXT: 401002: {{.*}}
// DISASM: _start:
-// 0x11013 + 5 - 24 = 0x11000
-// DISASM-NEXT: 11004: e9 27 00 00 00 jmp 39
-// DISASM-NEXT: 11009: e9 22 00 00 00 jmp 34
-// DISASM-NEXT: 1100e: e9 2d 00 00 00 jmp 45
-// DISASM-NEXT: 11013: e9 e8 ff ff ff jmp -24
+// 0x401013 + 5 - 24 = 0x401000
+// DISASM-NEXT: 401004: e9 27 00 00 00 jmp 39
+// DISASM-NEXT: 401009: e9 22 00 00 00 jmp 34
+// DISASM-NEXT: 40100e: e9 2d 00 00 00 jmp 45
+// DISASM-NEXT: 401013: e9 e8 ff ff ff jmp -24
-// 0x11010 - 0x1102b - 5 = -32
-// 0x11010 - 0x1103b - 5 = -48
-// 77828 = 0x13004 = .got.plt (0x13000) + 4
-// 77832 = 0x13008 = .got.plt (0x13000) + 8
-// 77836 = 0x1300C = .got.plt (0x13000) + got.plt.reserved(12)
-// 77840 = 0x13010 = .got.plt (0x13000) + got.plt.reserved(12) + 4
+// 0x401010 - 0x40102b - 5 = -32
+// 0x401010 - 0x40103b - 5 = -48
+// 4202500 = 0x402004 = .got.plt (0x402000) + 4
+// 4202504 = 0x402008 = .got.plt (0x402000) + 8
+// 4202508 = 0x40200C = .got.plt (0x402000) + got.plt.reserved(12)
+// 4202512 = 0x402010 = .got.plt (0x402000) + got.plt.reserved(12) + 4
// DISASM: Disassembly of section .plt:
// DISASM-NEXT: .plt:
-// DISASM-NEXT: 11020: ff 35 04 20 01 00 pushl 73732
-// DISASM-NEXT: 11026: ff 25 08 20 01 00 jmpl *73736
-// DISASM-NEXT: 1102c: 90 nop
-// DISASM-NEXT: 1102d: 90 nop
-// DISASM-NEXT: 1102e: 90 nop
-// DISASM-NEXT: 1102f: 90 nop
-// DISASM-NEXT: 11030: ff 25 0c 20 01 00 jmpl *73740
-// DISASM-NEXT: 11036: 68 00 00 00 00 pushl $0
-// DISASM-NEXT: 1103b: e9 e0 ff ff ff jmp -32 <.plt>
-// DISASM-NEXT: 11040: ff 25 10 20 01 00 jmpl *73744
-// DISASM-NEXT: 11046: 68 08 00 00 00 pushl $8
-// DISASM-NEXT: 1104b: e9 d0 ff ff ff jmp -48 <.plt>
+// DISASM-NEXT: 401020: ff 35 04 20 40 00 pushl 4202500
+// DISASM-NEXT: 401026: ff 25 08 20 40 00 jmpl *4202504
+// DISASM-NEXT: 40102c: 90 nop
+// DISASM-NEXT: 40102d: 90 nop
+// DISASM-NEXT: 40102e: 90 nop
+// DISASM-NEXT: 40102f: 90 nop
+// DISASM-EMPTY:
+// DISASM-NEXT: bar@plt:
+// DISASM-NEXT: 401030: ff 25 0c 20 40 00 jmpl *4202508
+// DISASM-NEXT: 401036: 68 00 00 00 00 pushl $0
+// DISASM-NEXT: 40103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: zed@plt:
+// DISASM-NEXT: 401040: ff 25 10 20 40 00 jmpl *4202512
+// DISASM-NEXT: 401046: 68 08 00 00 00 pushl $8
+// DISASM-NEXT: 40104b: e9 d0 ff ff ff jmp -48 <.plt>
// CHECKSHARED: Name: .plt
// CHECKSHARED-NEXT: Type: SHT_PROGBITS
diff --git a/test/ELF/plt.s b/test/ELF/plt.s
index cce60d732063..21f0f12f03ea 100644
--- a/test/ELF/plt.s
+++ b/test/ELF/plt.s
@@ -73,12 +73,18 @@
// DISASM-NEXT: 1020: ff 35 e2 0f 00 00 pushq 4066(%rip)
// DISASM-NEXT: 1026: ff 25 e4 0f 00 00 jmpq *4068(%rip)
// DISASM-NEXT: 102c: 0f 1f 40 00 nopl (%rax)
+// DISASM-EMPTY:
+// DISASM-NEXT: bar@plt:
// DISASM-NEXT: 1030: ff 25 e2 0f 00 00 jmpq *4066(%rip)
// DISASM-NEXT: 1036: 68 00 00 00 00 pushq $0
// DISASM-NEXT: 103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: zed@plt:
// DISASM-NEXT: 1040: ff 25 da 0f 00 00 jmpq *4058(%rip)
// DISASM-NEXT: 1046: 68 01 00 00 00 pushq $1
// DISASM-NEXT: 104b: e9 d0 ff ff ff jmp -48 <.plt>
+// DISASM-EMPTY:
+// DISASM-NEXT: _start@plt:
// DISASM-NEXT: 1050: ff 25 d2 0f 00 00 jmpq *4050(%rip)
// DISASM-NEXT: 1056: 68 02 00 00 00 pushq $2
// DISASM-NEXT: 105b: e9 c0 ff ff ff jmp -64 <.plt>
@@ -102,9 +108,13 @@
// DISASM2-NEXT: 201020: ff 35 e2 0f 00 00 pushq 4066(%rip)
// DISASM2-NEXT: 201026: ff 25 e4 0f 00 00 jmpq *4068(%rip)
// DISASM2-NEXT: 20102c: 0f 1f 40 00 nopl (%rax)
+// DISASM2-EMPTY:
+// DISASM2-NEXT: bar@plt:
// DISASM2-NEXT: 201030: ff 25 e2 0f 00 00 jmpq *4066(%rip)
// DISASM2-NEXT: 201036: 68 00 00 00 00 pushq $0
// DISASM2-NEXT: 20103b: e9 e0 ff ff ff jmp -32 <.plt>
+// DISASM2-EMPTY:
+// DISASM2-NEXT: zed@plt:
// DISASM2-NEXT: 201040: ff 25 da 0f 00 00 jmpq *4058(%rip)
// DISASM2-NEXT: 201046: 68 01 00 00 00 pushq $1
// DISASM2-NEXT: 20104b: e9 d0 ff ff ff jmp -48 <.plt>
diff --git a/test/ELF/ppc-relocs.s b/test/ELF/ppc-relocs.s
index 26810008bd12..40536b6f3768 100644
--- a/test/ELF/ppc-relocs.s
+++ b/test/ELF/ppc-relocs.s
@@ -55,6 +55,17 @@ mystr:
# CHECK: .FR_PPC_REL24:
# CHECK: 1101c: 48 00 00 04 b .+4
+.section .R_PPC_REL14,"ax",@progbits
+.globl .FR_PPC_REL14
+.FR_PPC_REL14:
+ beq .Lfooy
+.section .R_PPC_REL14_2,"ax",@progbits
+.Lfooy:
+
+# CHECK: Disassembly of section .R_PPC_REL14:
+# CHECK: .FR_PPC_REL14:
+# CHECK: 11020: {{.*}} bt 2, .+4
+
.section .R_PPC_REL32,"ax",@progbits
.globl .FR_PPC_REL32
.FR_PPC_REL32:
@@ -64,7 +75,7 @@ mystr:
# CHECK: Disassembly of section .R_PPC_REL32:
# CHECK: .FR_PPC_REL32:
-# CHECK: 11020: 00 00 00 04
+# CHECK: 11024: 00 00 00 04
.section .R_PPC_ADDR32,"ax",@progbits
.globl .FR_PPC_ADDR32
@@ -75,7 +86,7 @@ mystr:
# CHECK: Disassembly of section .R_PPC_ADDR32:
# CHECK: .FR_PPC_ADDR32:
-# CHECK: 11024: 00 01 10 28
+# CHECK: 11028: 00 01 10 2c
.align 2
.section .R_PPC_PLTREL24,"ax",@progbits
@@ -87,4 +98,4 @@ mystr:
# CHECK: Disassembly of section .R_PPC_PLTREL24:
# CHECK: .R_PPC_PLTREL24:
-# CHECK: 11028: 48 00 00 04 b .+4
+# CHECK: 1102c: 48 00 00 04 b .+4
diff --git a/test/ELF/ppc64-bsymbolic-toc-restore.s b/test/ELF/ppc64-bsymbolic-toc-restore.s
new file mode 100644
index 000000000000..49d347c48992
--- /dev/null
+++ b/test/ELF/ppc64-bsymbolic-toc-restore.s
@@ -0,0 +1,68 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-bsymbolic-local-def.s -o %t2.o
+# RUN: ld.lld -Bsymbolic -shared %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d -r %t | FileCheck %s
+# RUN: not ld.lld -shared %t1.o %t2.o -o %t 2>&1 | FileCheck --check-prefix=FAIL %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-bsymbolic-local-def.s -o %t2.o
+# RUN: ld.lld -Bsymbolic -shared %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d -r %t | FileCheck %s
+# RUN: not ld.lld -shared %t1.o %t2.o -o %t 2>&1 | FileCheck --check-prefix=FAIL %s
+
+# FAIL: call lacks nop, can't restore toc
+
+# Test to document the toc-restore behavior with -Bsymbolic option. Since
+# -Bsymbolic causes the call to bind to the internal defintion we know the
+# caller and callee share the same TOC base. This means branching to the
+# local entry point of the callee, and no need for a nop to follow the call
+# (since there is no need to restore the TOC-pointer after the call).
+
+ .abiversion 2
+ .section ".text"
+
+ .p2align 2
+ .global caller
+ .type caller, @function
+caller:
+.Lcaller_gep:
+ addis 2, 12, .TOC.-.Lcaller_gep@ha
+ addi 2, 2, .TOC.-.Lcaller_gep@l
+.Lcaller_lep:
+ .localentry caller, .-caller
+ mflr 0
+ std 0, -16(1)
+ stdu 1, -32(1)
+ bl def
+ mr 31, 3
+ bl not_defined
+ nop
+ add 3, 3, 31
+ addi 1, 1, 32
+ ld 0, -16(1)
+ mtlr 0
+ blr
+
+# Note that the bl .+44 is a call to def's local entry, jumping past the first 2
+# instructions. Branching to the global entry would corrupt the TOC pointer
+# since the global entry requires that %r12 hold the address of the function
+# being called.
+
+# CHECK-LABEL: caller
+# CHECK: bl .+44
+# CHECK-NEXT: mr 31, 3
+# CHECK-NEXT: bl .+67108816
+# CHECK-NEXT: ld 2, 24(1)
+# CHECK-NEXT: add 3, 3, 31
+# CHECK-NEXT: addi 1, 1, 32
+# CHECK-NEXT: ld 0, -16(1)
+# CHECK-NEXT: mtlr 0
+# CHECK-NEXT: blr
+# CHECK-EMPTY:
+# CHECK-NEXT: def:
+# CHECK-NEXT: addis 2, 12, 2
+# CHECK-NEXT: addi 2, 2, -32636
+# CHECK-NEXT: li 3, 55
+# CHECK-NEXT: blr
diff --git a/test/ELF/ppc64-call-reach.s b/test/ELF/ppc64-call-reach.s
new file mode 100644
index 000000000000..a02bfa829933
--- /dev/null
+++ b/test/ELF/ppc64-call-reach.s
@@ -0,0 +1,94 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET %s
+# RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s
+# RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s
+# RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \
+# RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld --defsym callee=0x12010010 --defsym tail_callee=0x12010020 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET %s
+# RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s
+# RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s
+# RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \
+# RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s
+
+# MISSALIGNED: ld.lld: error: {{.*}}.o:(.text+0x14): improper alignment for relocation R_PPC64_REL24: 0x19 is not aligned to 4 bytes
+# MISSALIGNED: ld.lld: error: {{.*}}.o:(.text+0x24): improper alignment for relocation R_PPC64_REL24: 0xB is not aligned to 4 bytes
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ mflr 0
+ std 0, 16(1)
+ stdu 1, 32(1)
+ bl callee
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ b tail_callee
+
+# Check that we are branching to the definitions, and not range-extending
+# thunks.
+# CHECK-LABEL: test
+# CHECK: 10010014: {{.*}} bl .+33554428
+# CHECK: 10010024: {{.*}} b .+33554428
+
+# NEGOFFSET-LABEL: test
+# NEGOFFSET: 10010014: {{.*}} bl .+33554432
+# NEGOFFSET: 10010024: {{.*}} b .+33554432
+
+# .branch_lt[0]
+# THUNK-LABEL: __long_branch_callee:
+# THUNK-NEXT: 10010000: {{.*}} addis 12, 2, -1
+# THUNK-NEXT: ld 12, -32768(12)
+# THUNK-NEXT: mtctr 12
+# THUNK-NEXT: bctr
+
+# .branch_lt[1]
+# THUNK-LABEL: __long_branch_tail_callee:
+# THUNK-NEXT: 10010010: {{.*}} addis 12, 2, -1
+# THUNK-NEXT: ld 12, -32760(12)
+# THUNK-NEXT: mtctr 12
+# THUNK-NEXT: bctr
+
+# Each call now branches to a thunk, and although it is printed as positive
+# the offset is interpreted as a signed 26 bit value so 67108812 is actually
+# -52.
+# THUNK-LABEL: test:
+# THUNK: 10010034: {{.*}} bl .+67108812
+# THUNK: 10010044: {{.*}} b .+67108812
+
+# The offset from the TOC to the .branch_lt section is (-1 << 16) - 32768.
+# Name Type Address Off Size
+# BRANCHLT: .branch_lt PROGBITS 0000000010020000 020000 000010
+# BRANCHLT: .got PROGBITS 0000000010030000 030000 000008
+# BRANCHLT-NOT: .plt
+
diff --git a/test/ELF/ppc64-dq.s b/test/ELF/ppc64-dq.s
new file mode 100644
index 000000000000..b29879d02353
--- /dev/null
+++ b/test/ELF/ppc64-dq.s
@@ -0,0 +1,32 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, qword@toc@ha
+ lxv 3, qword@toc@l(3)
+ addis 3, 2, qword@toc@ha
+ stxv 3, qword@toc@l(3)
+ blr
+
+ .comm qword, 16, 16
+
+# Verify that we don't overwrite any of the extended opcode bits on a DQ form
+# instruction.
+# CHECK-LABEL: test
+# CHECK: lxv 3, -32768(3)
+# CHECK: stxv 3, -32768(3)
diff --git a/test/ELF/ppc64-dtprel.s b/test/ELF/ppc64-dtprel.s
index 43922fa80382..e5ac83ac426a 100644
--- a/test/ELF/ppc64-dtprel.s
+++ b/test/ELF/ppc64-dtprel.s
@@ -2,15 +2,15 @@
// 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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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
diff --git a/test/ELF/ppc64_entry_point.s b/test/ELF/ppc64-entry-point.s
index a6f426c7eb10..6dbfc53d9abd 100644
--- a/test/ELF/ppc64_entry_point.s
+++ b/test/ELF/ppc64-entry-point.s
@@ -3,9 +3,11 @@
# 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-objdump -D %t2 | FileCheck -check-prefix=CHECK-LE %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
# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s
.text
@@ -36,14 +38,11 @@ _start:
// 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-LE: Disassembly of section .got:
+// CHECK-LE-NEXT: .got:
+// CHECK-LE-NEXT: 10020000: 00 80 02 10
+
// CHECK-BE: Disassembly of section .got:
// CHECK-BE-NEXT: .got:
// CHECK-BE-NEXT: 10020000: 00 00 00 00 {{.*}}
diff --git a/test/ELF/ppc64-error-missaligned-dq.s b/test/ELF/ppc64-error-missaligned-dq.s
new file mode 100644
index 000000000000..68ad2e5c46f8
--- /dev/null
+++ b/test/ELF/ppc64-error-missaligned-dq.s
@@ -0,0 +1,26 @@
+# REQUIRES: ppc
+#
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: improper alignment for relocation R_PPC64_TOC16_LO_DS: 0x8001 is not aligned to 16 bytes
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, qword@toc@ha
+ lxv 3, qword@toc@l(3)
+ blr
+
+ .comm pad, 1, 1
+ .comm qword, 16, 1
+
diff --git a/test/ELF/ppc64-error-missaligned-ds.s b/test/ELF/ppc64-error-missaligned-ds.s
new file mode 100644
index 000000000000..deee8f9caa1b
--- /dev/null
+++ b/test/ELF/ppc64-error-missaligned-ds.s
@@ -0,0 +1,26 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: improper alignment for relocation R_PPC64_TOC16_LO_DS: 0x8001 is not aligned to 4 bytes
+
+ .global test
+ .p2align 4
+ .type test,@function
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+.Llep:
+ .localentry test, .Llep-.Lgep
+ addis 3, 2, word@toc@ha
+ lwa 3, word@toc@l(3)
+ blr
+
+ .comm pad, 1, 1
+ .comm word, 4, 1
+
diff --git a/test/ELF/ppc64-func-entry-points.s b/test/ELF/ppc64-func-entry-points.s
index 640c94fe8cfb..1f23e6650a9c 100644
--- a/test/ELF/ppc64-func-entry-points.s
+++ b/test/ELF/ppc64-func-entry-points.s
@@ -75,6 +75,6 @@ glob:
// 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-NEXT: 10010088: {{.*}} nop
// 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
index 1a6cc5b5f2a0..121032cafdc8 100644
--- a/test/ELF/ppc64-gd-to-ie.s
+++ b/test/ELF/ppc64-gd-to-ie.s
@@ -5,16 +5,16 @@
# 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-objdump -d %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -r %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
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s
+# RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-general-dynamic-tls.s b/test/ELF/ppc64-general-dynamic-tls.s
index 66dab936575f..8ae25a91a087 100644
--- a/test/ELF/ppc64-general-dynamic-tls.s
+++ b/test/ELF/ppc64-general-dynamic-tls.s
@@ -2,17 +2,17 @@
// 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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-objdump -d %t.so | FileCheck --check-prefix=Dis %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-got-indirect.s b/test/ELF/ppc64-got-indirect.s
index 2837582c4d6b..d81700a83dd9 100644
--- a/test/ELF/ppc64-got-indirect.s
+++ b/test/ELF/ppc64-got-indirect.s
@@ -83,8 +83,8 @@ 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-NEXT: 10010008: {{.*}} nop
+# CHECK-NEXT: 1001000c: {{.*}} ld 3, -32760(2)
# CHECK: 1001001c: {{.*}} lwa 3, 0(3)
# CHECK-LE: Disassembly of section .data:
diff --git a/test/ELF/ppc64-got-off.s b/test/ELF/ppc64-got-off.s
new file mode 100644
index 000000000000..d3dff2262502
--- /dev/null
+++ b/test/ELF/ppc64-got-off.s
@@ -0,0 +1,67 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared --no-toc-optimize %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared --no-toc-optimize %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=OPT %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=OPT %s
+
+ .abiversion 2
+ .section ".text"
+
+ .p2align 2
+ .global func
+ .type func, @function
+func:
+.Lfunc_gep:
+ addis 2, 12, .TOC.-.Lfunc_gep@ha
+ addi 2, 2, .TOC.-.Lfunc_gep@l
+.Lfunc_lep:
+ .localentry func, .-func
+ addis 3, 2, a@got@ha
+ ld 3, a@got@l(3)
+ ld 4, a@got(2)
+ lis 5, a@got@h
+ ori 5, 5, a@got@l
+ li 6, 0
+ ori 6, 6, a@got
+ blr
+
+# CHECK-LABEL: func
+# CHECK: addis 3, 2, 0
+# CHECK-NEXT: ld 3, -32760(3)
+# CHECK-NEXT: ld 4, -32760(2)
+# CHECK-NEXT: lis 5, -1
+# CHECK-NEXT: ori 5, 5, 32776
+# CHECK-NEXT: li 6, 0
+# CHECK-NEXT: ori 6, 6, 32776
+
+# OPT-LABEL: func
+# OPT: nop
+# OPT-NEXT: ld 3, -32760(2)
+# OPT-NEXT: ld 4, -32760(2)
+# OPT-NEXT: lis 5, -1
+# OPT-NEXT: ori 5, 5, 32776
+# OPT-NEXT: li 6, 0
+# OPT-NEXT: ori 6, 6, 32776
+
+# Since the got entry for a is .got[1] and the TOC base points to
+# .got + 0x8000, the offset for a@got is -0x7FF8 --> -32760
+
+ .section ".data"
+ .global a
+ .type a, @object
+ .size a, 4
+ .p2align 2
+a:
+ .long 0x1000
diff --git a/test/ELF/ppc64-initial-exec-tls.s b/test/ELF/ppc64-initial-exec-tls.s
index 5218b68828ee..9cdd3e4375c4 100644
--- a/test/ELF/ppc64-initial-exec-tls.s
+++ b/test/ELF/ppc64-initial-exec-tls.s
@@ -4,19 +4,19 @@
// 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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-objdump -d %t | FileCheck --check-prefix=Dis %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-local-dynamic.s b/test/ELF/ppc64-local-dynamic.s
index 57f324edbc63..6ed3b0fd8f07 100644
--- a/test/ELF/ppc64-local-dynamic.s
+++ b/test/ELF/ppc64-local-dynamic.s
@@ -2,17 +2,17 @@
// 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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-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-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %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-objdump -d %t.so | FileCheck --check-prefix=Dis %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-local-exec-tls.s b/test/ELF/ppc64-local-exec-tls.s
index ff8c2b90102c..27e973dc4eb1 100644
--- a/test/ELF/ppc64-local-exec-tls.s
+++ b/test/ELF/ppc64-local-exec-tls.s
@@ -1,8 +1,8 @@
// 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
+// RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-long-branch.s b/test/ELF/ppc64-long-branch.s
new file mode 100644
index 000000000000..db662d926df0
--- /dev/null
+++ b/test/ELF/ppc64-long-branch.s
@@ -0,0 +1,121 @@
+# 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: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t
+# RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP
+# RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP
+# RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_LE
+# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS
+
+# 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: ld.lld -shared %t2.o -o %t3.so
+# RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t
+# RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP
+# RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP
+# RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_BE
+# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS
+
+ .text
+ .abiversion 2
+ .protected callee
+ .globl callee
+ .p2align 4
+ .type callee,@function
+callee:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry callee, .Lfunc_lep0-.Lfunc_gep0
+ addis 4, 2, .LC0@toc@ha
+ ld 4, .LC0@toc@l(4)
+ lwz 3, 0(4)
+ blr
+
+ .space 0x2000000
+
+ .protected _start
+ .global _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin1:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry _start, .Lfunc_lep1-.Lfunc_gep1
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl callee
+ bl foo_external_diff
+ nop
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+
+ addis 4, 2, .LC1@toc@ha
+ ld 4, .LC1@toc@l(4)
+ lwz 4, 0(4)
+ add 3, 3, 4
+ blr
+
+
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc a[TC],a
+.LC1:
+ .tc b[TC],b
+
+
+ .data
+ .type a,@object
+ .globl a
+ .p2align 2
+a:
+ .long 11
+ .size a, 4
+
+ .type b,@object
+ .global b
+ .p2align 2
+b:
+ .long 33
+ .size b, 4
+
+# Verify address of the callee
+# CALLEE_DUMP: callee:
+# CALLEE_DUMP: 10010000: {{.*}} addis 2, 12, 515
+# CALLEE_DUMP: 10010004: {{.*}} addi 2, 2, -32544
+# CALLEE_DUMP: 10010008: {{.*}} addis 4, 2, 0
+
+# Verify the address of _start, and the call to the long-branch thunk.
+# CALLER_DUMP: _start:
+# CALLER_DUMP: 12010020: {{.*}} addis 2, 12, 3
+# CALLER_DUMP: 12010038: {{.*}} bl .+56
+
+# Verify the thunks contents: TOC-pointer + offset = .branch_lt[0]
+# 0x120380e8 + (-2 << 16 + 32552) = 0x12020008
+# CALLER_DUMP: __long_branch_callee:
+# CALLER_DUMP: 12010060: {{.*}} addis 12, 2, -2
+# CALLER_DUMP: 12010064: {{.*}} ld 12, 32552(12)
+# CALLER_DUMP: 12010068: {{.*}} mtctr 12
+# CALLER_DUMP: 1201006c: {{.*}} bctr
+
+# BRANCH_LT_LE: Disassembly of section .branch_lt:
+# BRANCH_LT_LE-NEXT: .branch_lt:
+# BRANCH_LT_LE-NEXT: 12020008: 08 00 01 10
+# BRANCH_LT_LE-NEXT: 1202000c: 00 00 00 00
+
+# BRANCH_LT_BE: Disassembly of section .branch_lt:
+# BRANCH_LT_BE-NEXT: .branch_lt:
+# BRANCH_LT_BE-NEXT: 12020008: 00 00 00 00
+# BRANCH_LT_BE-NEXT: 1202000c: 10 01 00 08
+
+# [Nr] Name Type Address Off Size
+# SECTIONS: [ 9] .branch_lt PROGBITS 0000000012020008 2020008 000008
+# SECTIONS: [11] .got PROGBITS 00000000120300e0 20300e0 000008
diff --git a/test/ELF/ppc64-rel-so-local-calls.s b/test/ELF/ppc64-rel-so-local-calls.s
index 834dbd50aa90..2bc89d554a02 100644
--- a/test/ELF/ppc64-rel-so-local-calls.s
+++ b/test/ELF/ppc64-rel-so-local-calls.s
@@ -1,11 +1,11 @@
// 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: ld.lld -shared %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: ld.lld -shared %t.o -o %t.so
// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s
diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s
index 88e3d4b13e5d..b439c4446654 100644
--- a/test/ELF/ppc64-relocs.s
+++ b/test/ELF/ppc64-relocs.s
@@ -63,7 +63,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_TOC16_HA:
# CHECK: .FR_PPC64_TOC16_HA:
-# CHECK: 10010018: {{.*}} addis 1, 2, 0
+# CHECK: 10010018: {{.*}} nop
.section .R_PPC64_REL24,"ax",@progbits
.globl .FR_PPC64_REL24
@@ -76,6 +76,17 @@ _start:
# CHECK: .FR_PPC64_REL24:
# CHECK: 1001001c: {{.*}} b .+4
+.section .R_PPC64_REL14,"ax",@progbits
+.globl .FR_PPC64_REL14
+.FR_PPC64_REL14:
+ beq .Lfooy
+.section .R_PPC64_REL14_2,"ax",@progbits
+.Lfooy:
+
+# CHECK: Disassembly of section .R_PPC64_REL14:
+# CHECK: .FR_PPC64_REL14:
+# CHECK: 10010020: {{.*}} bt 2, .+4
+
.section .R_PPC64_ADDR16_LO,"ax",@progbits
.globl .FR_PPC64_ADDR16_LO
.FR_PPC64_ADDR16_LO:
@@ -83,7 +94,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_LO:
# CHECK: .FR_PPC64_ADDR16_LO:
-# CHECK: 10010020: {{.*}} li 1, 0
+# CHECK: 10010024: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HI,"ax",@progbits
.globl .FR_PPC64_ADDR16_HI
@@ -92,7 +103,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HI:
# CHECK: .FR_PPC64_ADDR16_HI:
-# CHECK: 10010024: {{.*}} li 1, 4097
+# CHECK: 10010028: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HA
@@ -101,7 +112,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HA:
# CHECK: .FR_PPC64_ADDR16_HA:
-# CHECK: 10010028: {{.*}} li 1, 4097
+# CHECK: 1001002c: {{.*}} li 1, 4097
.section .R_PPC64_ADDR16_HIGHER,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHER
@@ -110,7 +121,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER:
# CHECK: .FR_PPC64_ADDR16_HIGHER:
-# CHECK: 1001002c: {{.*}} li 1, 0
+# CHECK: 10010030: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHERA
@@ -119,7 +130,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA:
# CHECK: .FR_PPC64_ADDR16_HIGHERA:
-# CHECK: 10010030: {{.*}} li 1, 0
+# CHECK: 10010034: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHEST
@@ -128,7 +139,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST:
# CHECK: .FR_PPC64_ADDR16_HIGHEST:
-# CHECK: 10010034: {{.*}} li 1, 0
+# CHECK: 10010038: {{.*}} li 1, 0
.section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits
.globl .FR_PPC64_ADDR16_HIGHESTA
@@ -137,7 +148,7 @@ _start:
# CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA:
# CHECK: .FR_PPC64_ADDR16_HIGHESTA:
-# CHECK: 10010038: {{.*}} li 1, 0
+# CHECK: 1001003c: {{.*}} li 1, 0
.section .R_PPC64_REL32, "ax",@progbits
.globl .FR_PPC64_REL32
@@ -149,20 +160,20 @@ _start:
# DATALE: Disassembly of section .rodata:
# DATALE: .rodata:
-# DATALE: 10000190: b4 fe 00 00
+# DATALE: 10000190: b8 fe 00 00
# DATABE: Disassembly of section .rodata:
# DATABE: .rodata:
-# DATABE: 10000190: 00 00 fe b4
+# DATABE: 10000190: 00 00 fe b8
# 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
+# CHECK: 10010040: {{.*}} nop
+# CHECK: 10010044: {{.*}} ld 5, -32736(2)
+# CHECK: 10010048: {{.*}} add 3, 3, 4
.section .R_PPC64_REL64, "ax",@progbits
.globl .FR_PPC64_REL64
@@ -178,16 +189,16 @@ __foo:
# 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
+# the entry is not stored exactly at 10000198. It starts at
+# address 0x1000019a and has the value 0xfeaa.
+# 0x100001aa + 0xfeae = 0x10010058
# DATALE: Disassembly of section .eh_frame:
# DATALE: .eh_frame:
-# DATALE: 100001a8: {{.*}} aa fe
+# DATALE: 100001a8: {{.*}} ae fe
# DATABE: Disassembly of section .eh_frame:
# DATABE: .eh_frame:
-# DATABE: 100001b0: fe aa {{.*}}
+# DATABE: 100001b0: fe ae {{.*}}
# CHECK: __foo
-# CHECK-NEXT: 10010054: {{.*}} li 3, 0
+# CHECK-NEXT: 10010058: {{.*}} li 3, 0
diff --git a/test/ELF/ppc64-shared-long_branch.s b/test/ELF/ppc64-shared-long_branch.s
new file mode 100644
index 000000000000..34d53147a551
--- /dev/null
+++ b/test/ELF/ppc64-shared-long_branch.s
@@ -0,0 +1,114 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld --no-toc-optimize -shared %t.o -o %t
+# RUN: llvm-objdump -d -start-address=0x10000 -stop-address=0x10018 %t | FileCheck %s -check-prefix=CALLEE_DUMP
+# RUN: llvm-objdump -d -start-address=0x2010020 -stop-address=0x2010070 %t | FileCheck %s -check-prefix=CALLER_DUMP
+# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS
+# RUN: llvm-readelf --relocations %t | FileCheck %s -check-prefix=DYNRELOC
+
+
+# _start calls protected function callee. Since callee is protected no plt stub
+# is needed. The binary however has been padded out with space so that the call
+# distance is further then a bl instrution can reach.
+
+ .text
+ .abiversion 2
+ .protected callee
+ .global callee
+ .p2align 4
+ .type callee,@function
+callee:
+.Lfunc_gep0:
+ addis 2, 12, .TOC.-.Lfunc_gep0@ha
+ addi 2, 2, .TOC.-.Lfunc_gep0@l
+.Lfunc_lep0:
+ .localentry callee, .Lfunc_lep0-.Lfunc_gep0
+ addis 4, 2, .LC0@toc@ha
+ ld 4, .LC0@toc@l(4)
+ lwz 3, 0(4)
+ blr
+
+ .space 0x2000000
+
+ .protected _start
+ .globl _start
+ .p2align 4
+ .type _start,@function
+_start:
+.Lfunc_begin1:
+.Lfunc_gep1:
+ addis 2, 12, .TOC.-.Lfunc_gep1@ha
+ addi 2, 2, .TOC.-.Lfunc_gep1@l
+.Lfunc_lep1:
+ .localentry _start, .Lfunc_lep1-.Lfunc_gep1
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl callee
+ bl ext_callee
+ nop
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+
+ addis 4, 2, .LC1@toc@ha
+ ld 4, .LC1@toc@l(4)
+ lwz 4, 0(4)
+ add 3, 3, 4
+ blr
+
+
+ .section .toc,"aw",@progbits
+.LC0:
+ .tc a[TC],a
+.LC1:
+ .tc b[TC],b
+
+
+ .data
+ .type a,@object
+ .globl a
+ .p2align 2
+a:
+ .long 11
+ .size a, 4
+
+ .type b,@object
+ .globl b
+ .p2align 2
+b:
+ .long 33
+ .size b, 4
+
+# Verify address of the callee
+# CALLEE_DUMP: callee:
+# CALLEE_DUMP: 10000: {{.*}} addis 2, 12, 515
+# CALLEE_DUMP: 10004: {{.*}} addi 2, 2, -32528
+# CALLEE_DUMP: 10008: {{.*}} addis 4, 2, 0
+
+# Verify the address of _start, and the call to the long-branch thunk.
+# CALLER_DUMP: _start:
+# CALLER_DUMP: 2010020: {{.*}} addis 2, 12, 3
+# CALLER_DUMP: 2010038: {{.*}} bl .+56
+
+# Verify the thunks contents: TOC-pointer + offset = .branch_lt[0]
+# 0x20380F0 + 32552 = 0x2040018
+# CALLER_DUMP: __long_branch_callee:
+# CALLER_DUMP: 2010060: {{.*}} addis 12, 2, 0
+# CALLER_DUMP: 2010064: {{.*}} ld 12, 32552(12)
+# CALLER_DUMP: 2010068: {{.*}} mtctr 12
+# CALLER_DUMP: 201006c: {{.*}} bctr
+
+# .got section is at address 0x20300f0 so TOC pointer points to 0x20400F0.
+# .plt section has a 2 entry header and a single entry for the long branch.
+# [Nr] Name Type Address Off Size
+# SECTIONS: [11] .got PROGBITS 00000000020300f0 20300f0 000008
+# SECTIONS: [13] .plt NOBITS 0000000002040000 2030108 000018
+# SECTIONS: [14] .branch_lt NOBITS 0000000002040018 2030108 000008
+
+# There is a relative dynamic relocation for (.plt + 16 bytes), with a base
+# address equal to callees local entry point (0x10000 + 8).
+# DYNRELOC: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries:
+# DYNRELOC: Offset Info Type Symbol's Value
+# DYNRELOC: 0000000002040018 0000000000000016 R_PPC64_RELATIVE 10008
diff --git a/test/ELF/ppc64-split-stack-adjust-fail.s b/test/ELF/ppc64-split-stack-adjust-fail.s
new file mode 100644
index 000000000000..4ad1a9994d98
--- /dev/null
+++ b/test/ELF/ppc64-split-stack-adjust-fail.s
@@ -0,0 +1,53 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: not ld.lld --defsym __morestack=0x10010000 %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: not ld.lld --defsym __morestack=0x10010000 %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+
+# CHECK: error: {{.*}}.o:(.text): wrong_regs (with -fsplit-stack) calls nss_callee (without -fsplit-stack), but couldn't adjust its prologue
+
+ .abiversion 2
+ .section ".text"
+
+ .p2align 2
+ .global wrong_regs
+ .type wrong_regs, @function
+
+wrong_regs:
+.Lwr_gep:
+ addis 2, 12, .TOC.-.Lwr_gep@ha
+ addi 2, 2, .TOC.-.Lwr_gep@l
+ .localentry wrong_regs, .-wrong_regs
+ ld 0, -0x7040(13)
+ addis 5, 2, -1
+ addi 5, 5, -32
+ addi 12, 1, -32
+ nop
+ cmpld 7, 12, 0
+ blt- 7, .Lwr_alloc_more
+.Lwr_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl nss_callee
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lwr_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lwr_body
+ .size wrong_regs, .-wrong_regs
+
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/ppc64-split-stack-adjust-overflow.s b/test/ELF/ppc64-split-stack-adjust-overflow.s
new file mode 100644
index 000000000000..874f45cd0e7d
--- /dev/null
+++ b/test/ELF/ppc64-split-stack-adjust-overflow.s
@@ -0,0 +1,64 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: not ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 2>&1 | \
+# RUN: FileCheck -check-prefix=OVERFLOW %s
+# RUN: not ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 \
+# RUN: -split-stack-adjust-size 4097 2>&1 | FileCheck -check-prefix=OVERFLOW %s
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 4096
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: not ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 2>&1 | \
+# RUN: FileCheck -check-prefix=OVERFLOW %s
+# RUN: not ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 \
+# RUN: -split-stack-adjust-size 4097 2>&1 | FileCheck -check-prefix=OVERFLOW %s
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 4096
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# OVERFLOW: error: {{.*}}.o:(function caller: .text+0x8): split-stack prologue adjustment overflows
+
+ .p2align 2
+ .global caller
+ .type caller, @function
+caller:
+.Lcaller_gep:
+ addis 2, 12, .TOC.-.Lcaller_gep@ha
+ addi 2, 2, .TOC.-.Lcaller_gep@l
+ .localentry caller, .-caller
+ ld 0, -0x7040(13)
+ addis 12, 1, -32768
+ addi 12, 12, 4096
+ cmpld 7, 12, 0
+ blt- 7, .Lcaller_alloc_more
+.Lcaller_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl nss_callee
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lcaller_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lcaller_body
+ .size caller, .-caller
+
+# CHECK-LABEL: caller
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addis 12, 1, -32768
+# CHECK-NEXT: nop
+# CHECK-NEXT: cmpld 7, 12, 0
+# CHECK-NEXT: bt- 28, .+36
+
+.section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/ppc64-split-stack-adjust-size-success.s b/test/ELF/ppc64-split-stack-adjust-size-success.s
new file mode 100644
index 000000000000..913d2625e92a
--- /dev/null
+++ b/test/ELF/ppc64-split-stack-adjust-size-success.s
@@ -0,0 +1,108 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 32768
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 4096
+# RUN: llvm-objdump -d %t | FileCheck %s -check-prefix=SMALL
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 0
+# RUN: llvm-objdump -d %t | FileCheck %s -check-prefix=ZERO
+# RUN: not ld.lld %t1.o %t2.o -o %t -split-stack-adjust-size -1 2>&1 | FileCheck %s -check-prefix=ERR
+# ERR: error: --split-stack-adjust-size: size must be >= 0
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 32768
+# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 4096
+# RUN: llvm-objdump -d %t | FileCheck %s -check-prefix=SMALL
+# RUN: ld.lld %t1.o %t2.o -o %t --defsym __morestack=0x10010000 -split-stack-adjust-size 0
+# RUN: llvm-objdump -d %t | FileCheck %s -check-prefix=ZERO
+ .p2align 2
+ .global caller
+ .type caller, @function
+caller:
+.Lcaller_gep:
+ addis 2, 12, .TOC.-.Lcaller_gep@ha
+ addi 2, 2, .TOC.-.Lcaller_gep@l
+ .localentry caller, .-caller
+ ld 0, -0x7040(13)
+ addi 12, 1, -32
+ nop
+ cmpld 7, 12, 0
+ blt- 7, .Lcaller_alloc_more
+.Lcaller_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl nss_callee
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lcaller_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lcaller_body
+ .size caller, .-caller
+
+# CHECK-LABEL: caller
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addis 12, 1, -1
+# CHECK-NEXT: addi 12, 12, 32736
+# CHECK-NEXT: cmpld 7, 12, 0
+# CHECK-NEXT: bt- 28, .+36
+
+# SMALL-LABEL: caller
+# SMALL: ld 0, -28736(13)
+# SMALL-NEXT: addi 12, 1, -4128
+# SMALL-NEXT: nop
+# SMALL-NEXT: cmpld 7, 12, 0
+# SMALL-NEXT: bt- 28, .+36
+
+# ZERO-LABEL: caller
+# ZERO: ld 0, -28736(13)
+# ZERO-NEXT: addi 12, 1, -32
+# ZERO-NEXT: nop
+# ZERO-NEXT: cmpld 7, 12, 0
+# ZERO-NEXT: bt- 28, .+36
+ .p2align 2
+ .global main
+ .type main, @function
+main:
+.Lmain_gep:
+ addis 2,12,.TOC.-.Lmain_gep@ha
+ addi 2,2,.TOC.-.Lmain_gep@l
+ .localentry main,.-main
+ ld 0,-0x7040(13)
+ addi 12,1,-32
+ nop
+ cmpld 7,12,0
+ blt- 7, .Lmain_morestack
+.Lmain_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl caller
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lmain_morestack:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lmain_body
+ .size main,.-main
+
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/ppc64-split-stack-prologue-adjust-success.s b/test/ELF/ppc64-split-stack-prologue-adjust-success.s
new file mode 100644
index 000000000000..197df150c495
--- /dev/null
+++ b/test/ELF/ppc64-split-stack-prologue-adjust-success.s
@@ -0,0 +1,224 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+# RUN: ld.lld --defsym __morestack=0x10010000 %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t1.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-no-split-stack.s -o %t2.o
+# RUN: ld.lld --defsym __morestack=0x10010000 %t1.o %t2.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+ .abiversion 2
+ .section ".text"
+
+
+# A caller with a stack that is small enough that the addis instruction
+# from the split-stack prologue is unneeded, and after the prologue adjustment
+# the stack size still fits whithin 16 bits.
+ .p2align 2
+ .global caller_small_stack
+ .type caller_small_stack, @function
+caller_small_stack:
+.Lcss_gep:
+ addis 2, 12, .TOC.-.Lcss_gep@ha
+ addi 2, 2, .TOC.-.Lcss_gep@l
+ .localentry caller_small_stack, .-caller_small_stack
+ ld 0, -0x7040(13)
+ addi 12, 1, -32
+ nop
+ cmpld 7, 12, 0
+ blt- 7, .Lcss_alloc_more
+.Lcss_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl nss_callee
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lcss_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lcss_body
+ .size caller_small_stack, .-caller_small_stack
+
+# CHECK-LABEL: caller_small_stack
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addi 12, 1, -16416
+# CHECK-NEXT: nop
+# CHECK-NEXT: cmpld 7, 12, 0
+# CHECK-NEXT: bt- 28, .+36
+
+# A caller that has a stack size that fits whithin 16 bits, but the adjusted
+# stack size after prologue adjustment now overflows 16 bits needing both addis
+# and addi instructions.
+ .p2align 2
+ .global caller_med_stack
+ .type caller_med_stack, @function
+caller_med_stack:
+.Lcms_gep:
+ addis 2, 12, .TOC.-.Lcms_gep@ha
+ addi 12, 12, .TOC.-.Lcms_gep@l
+ .localentry caller_med_stack, .-caller_med_stack
+ ld 0, -0x7040(13)
+ addi 12, 1, -32764
+ nop
+ cmpld 7, 12, 0
+ blt- 7, .Lcms_alloc_more
+.Lcms_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32764(1)
+ bl nss_callee
+ addi 1, 1, 32764
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lcms_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lcms_body
+ .size caller_med_stack, .-caller_med_stack
+
+# A caller with a large enough stack frame that both the addis and
+# addi instructions are used in the split-stack prologue.
+ .p2align 2
+ .global caller_large_stack
+ .type caller_large_stack, @function
+caller_large_stack:
+.Lcls_gep:
+ addis 2, 12, .TOC.-.Lcls_gep@ha
+ addi 12, 12, .TOC.-.Lcls_gep@l
+ .localentry caller_large_stack, .-caller_large_stack
+ ld 0, -0x7040(13)
+ addis 12, 1, -1
+ addi 12, 12, -32
+ cmpld 7, 12, 0
+ blt- 7, .Lcls_alloc_more
+.Lcls_body:
+ mflr 0
+ std 0, 16(1)
+ lis 0, -1
+ addi 0, 0, -32
+ stdux 1, 0, 1
+ bl nss_callee
+ ld 1, 0(1)
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lcls_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lcls_body
+ .size caller_large_stack, .-caller_large_stack
+
+# CHECK-LABEL: caller_large_stack
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addis 12, 1, -1
+# CHECK-NEXT: addi 12, 12, -16416
+# CHECK-NEXT: cmpld 7, 12, 0
+# CHECK-NEXT: bt- 28, .+44
+
+# A caller with a stack size that is larger then 16 bits, but aligned such that
+# the addi instruction is unneeded.
+ .p2align 2
+ .global caller_large_aligned_stack
+ .type caller_large_aligned_stack, @function
+caller_large_aligned_stack:
+.Lclas_gep:
+ addis 2, 12, .TOC.-.Lclas_gep@ha
+ addi 12, 12, .TOC.-.Lclas_gep@l
+ .localentry caller_large_aligned_stack, .-caller_large_aligned_stack
+ ld 0, -0x7040(13)
+ addis 12, 1, -2
+ nop
+ cmpld 7, 12, 0
+ blt- 7, .Lclas_alloc_more
+.Lclas_body:
+ mflr 0
+ std 0, 16(1)
+ lis 0, -2
+ stdux 1, 0, 1
+ bl nss_callee
+ ld 1, 0(1)
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lclas_alloc_more:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lclas_body
+ .size caller_large_aligned_stack, .-caller_large_aligned_stack
+
+# CHECK-LABEL: caller_large_aligned_stack
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addis 12, 1, -2
+# CHECK-NEXT: addi 12, 12, -16384
+# CHECK-NEXT: cmpld 7, 12, 0
+# CHECK-NEXT: bt- 28, .+40
+
+# main only calls split-stack functions or __morestack so
+# there should be no adjustment of its split-stack prologue.
+ .p2align 2
+ .global main
+ .type main, @function
+main:
+.Lmain_gep:
+ addis 2, 12,.TOC.-.Lmain_gep@ha
+ addi 2, 2,.TOC.-.Lmain_gep@l
+ .localentry main,.-main
+ ld 0, -0x7040(13)
+ addi 12,1,-32
+ nop
+ cmpld 7, 12,0
+ blt- 7, .Lmain_morestack
+.Lmain_body:
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ bl caller_small_stack
+ nop
+ bl caller_med_stack
+ nop
+ bl caller_large_stack
+ nop
+ bl caller_large_aligned_stack
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+.Lmain_morestack:
+ mflr 0
+ std 0, 16(1)
+ bl __morestack
+ ld 0, 16(1)
+ mtlr 0
+ blr
+ b .Lmain_body
+ .size main,.-main
+# CHECK-LABEL: main
+# CHECK: ld 0, -28736(13)
+# CHECK-NEXT: addi 12, 1, -32
+# CHECK-NEXT: nop
+# CHECK-NEXT: cmpld 7, 12, 0
+
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/ppc64-tls-gd-le-small.s b/test/ELF/ppc64-tls-gd-le-small.s
new file mode 100644
index 000000000000..f5a1ec6f01d6
--- /dev/null
+++ b/test/ELF/ppc64-tls-gd-le-small.s
@@ -0,0 +1,61 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-objdump -d -r %t.o | FileCheck --check-prefix=CHECK-INPUT %s
+# RUN: ld.lld --defsym __tls_get_addr=0x10001000 %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=CHECK-DIS %s
+# RUN: llvm-readelf -relocations %t | FileCheck --check-prefix=DYN-RELOCS %s
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-objdump -d -r %t.o | FileCheck --check-prefix=CHECK-INPUT %s
+# RUN: ld.lld --defsym __tls_get_addr=0x10001000 %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=CHECK-DIS %s
+# RUN: llvm-readelf -relocations %t | FileCheck --check-prefix=DYN-RELOCS %s
+
+# Test checks the relaxation of a 'small' general-dynamic tls access into a
+# local-exec tls access.
+
+ .text
+ .abiversion 2
+
+ .global test
+ .p2align 4
+ .type test, @function
+
+test:
+.Lgep:
+ addis 2, 12, .TOC.-.Lgep@ha
+ addi 2, 2, .TOC.-.Lgep@l
+ .localentry test, .-test
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addi 3, 2, a@got@tlsgd
+ bl __tls_get_addr(a@tlsgd)
+ nop
+ lwz 3, 0(3)
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+ blr
+
+ .type a, @object
+ .section .tdata,"awT",@progbits
+ .global a
+ .p2align 2
+a:
+ .long 55
+ .size a, 4
+
+# CHECK-INPUT: addi 3, 2, 0
+# CHECK-INPUT-NEXT: R_PPC64_GOT_TLSGD16 a
+# CHECK-INPUT-NEXT: bl .+0
+# CHECK-INPUT-NEXT: R_PPC64_TLSGD a
+# CHECK-INPUT-NEXT: R_PPC64_REL24 __tls_get_addr
+
+# CHECK-DIS: addis 3, 13, 0
+# CHECK-DIS-NEXT: nop
+# CHECK-DIS-NEXT: addi 3, 3, -28672
+# CHECK-DIS-NEXT: lwz 3, 0(3)
+
+# DYN-RELOCS: There are no relocations in this file
diff --git a/test/ELF/ppc64-tls-gd-le.s b/test/ELF/ppc64-tls-gd-le.s
index c55ae5f670c1..7907d1104a2b 100644
--- a/test/ELF/ppc64-tls-gd-le.s
+++ b/test/ELF/ppc64-tls-gd-le.s
@@ -1,16 +1,16 @@
// 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: llvm-readelf -r %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-objdump -d %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -r %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: llvm-readelf -r %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-objdump -d %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-tls-ie-le.s b/test/ELF/ppc64-tls-ie-le.s
new file mode 100644
index 000000000000..358d3e862b62
--- /dev/null
+++ b/test/ELF/ppc64-tls-ie-le.s
@@ -0,0 +1,140 @@
+// 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-ie-le.s -o %t2.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t
+// RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %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-ie-le.s -o %t2.o
+// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o -o %t
+// RUN: llvm-readelf -r %t.o | FileCheck --check-prefix=InputRelocs %s
+// RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=Dis %s
+
+ .text
+ .abiversion 2
+test1: # @test1
+ addis 3, 2, c@got@tprel@ha
+ ld 3, c@got@tprel@l(3)
+ lbzx 3, 3, c@tls
+ blr
+test2: # @test2
+ addis 3, 2, s@got@tprel@ha
+ ld 3, s@got@tprel@l(3)
+ lhzx 3, 3, s@tls
+ blr
+test3: # @test3
+ addis 3, 2, i@got@tprel@ha
+ ld 3, i@got@tprel@l(3)
+ lwzx 3, 3, i@tls
+ blr
+test4: # @test4
+ addis 3, 2, l@got@tprel@ha
+ ld 3, l@got@tprel@l(3)
+ ldx 3, 3, l@tls
+ blr
+test5: # @test5
+ addis 4, 2, c@got@tprel@ha
+ ld 4, c@got@tprel@l(4)
+ stbx 3, 4, c@tls
+ blr
+test6: # @test6
+ addis 4, 2, s@got@tprel@ha
+ ld 4, s@got@tprel@l(4)
+ sthx 3, 4, s@tls
+ blr
+test7: # @test7
+ addis 4, 2, i@got@tprel@ha
+ ld 4, i@got@tprel@l(4)
+ stwx 3, 4, i@tls
+ blr
+test8: # @test8
+ addis 4, 2, l@got@tprel@ha
+ ld 4, l@got@tprel@l(4)
+ stdx 3, 4, l@tls
+ blr
+test9: # @test9
+ addis 3, 2, i@got@tprel@ha
+ ld 3, i@got@tprel@l(3)
+ add 3, 3, i@tls
+ blr
+test_ds: # @test_ds
+ ld 4, l@got@tprel(2)
+ stdx 3, 4, l@tls
+ blr
+
+
+// Verify that the input has initial-exec tls relocation types.
+// InputRelocs: Relocation section '.rela.text'
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} c + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} c + 0
+// InputRelocs: R_PPC64_TLS {{0+}} c + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} s + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} s + 0
+// InputRelocs: R_PPC64_TLS {{0+}} s + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} i + 0
+// InputRelocs: R_PPC64_TLS {{0+}} i + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} l + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} l + 0
+// InputRelocs: R_PPC64_TLS {{0+}} l + 0
+// InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} l + 0
+// InputRelocs: R_PPC64_TLS {{0+}} l + 0
+
+// Verify that no initial-exec relocations exist for the dynamic linker.
+// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} c + 0
+// OutputRelocs-NPT: R_PPC64_TPREL64 {{0+}} s + 0
+// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} i + 0
+// OutputRelocs-NOT: R_PPC64_TPREL64 {{0+}} l + 0
+
+// Dis: test1:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: lbz 3, -28672(3)
+
+// Dis: test2:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: lhz 3, -28670(3)
+
+// Dis: test3:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: lwz 3, -28668(3)
+
+// Dis: test4:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: ld 3, -28664(3)
+
+// Dis: test5:
+// Dis: nop
+// Dis: addis 4, 13, 0
+// Dis: stb 3, -28672(4)
+
+// Dis: test6:
+// Dis: nop
+// Dis: addis 4, 13, 0
+// Dis: sth 3, -28670(4)
+
+// Dis: test7:
+// Dis: nop
+// Dis: addis 4, 13, 0
+// Dis: stw 3, -28668(4)
+
+// Dis: test8:
+// Dis: nop
+// Dis: addis 4, 13, 0
+// Dis: std 3, -28664(4)
+
+// Dis: test9:
+// Dis: nop
+// Dis: addis 3, 13, 0
+// Dis: addi 3, 3, -28668
+
+// Dis: test_ds:
+// Dis: addis 4, 13, 0
+// Dis: std 3, -28664(4)
diff --git a/test/ELF/ppc64-tls-ld-le.s b/test/ELF/ppc64-tls-ld-le.s
index d42d7b983c84..b684515e8b04 100644
--- a/test/ELF/ppc64-tls-ld-le.s
+++ b/test/ELF/ppc64-tls-ld-le.s
@@ -1,16 +1,16 @@
// 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: llvm-readelf -r %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-objdump -d %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -r %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: llvm-readelf -r %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-objdump -d %t | FileCheck --check-prefix=Dis %s
+// RUN: llvm-readelf -r %t | FileCheck --check-prefix=OutputRelocs %s
.text
.abiversion 2
diff --git a/test/ELF/ppc64-toc-addis-nop-lqsq.s b/test/ELF/ppc64-toc-addis-nop-lqsq.s
new file mode 100644
index 000000000000..da57f38804a4
--- /dev/null
+++ b/test/ELF/ppc64-toc-addis-nop-lqsq.s
@@ -0,0 +1,73 @@
+# REQUIRES: ppc
+
+# RUN: llvm-readelf -relocations --wide %p/Inputs/ppc64le-quadword-ldst.o | FileCheck --check-prefix=QuadInputRelocs %s
+
+# 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 %t2.so %p/Inputs/ppc64le-quadword-ldst.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+
+# RUN: ld.lld --no-toc-optimize %t2.so %p/Inputs/ppc64le-quadword-ldst.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=NoOpt %s
+
+# QuadInputRelocs: Relocation section '.rela.text'
+# QuadInputRelocs: R_PPC64_TOC16_LO_DS 0000000000000000 quadLd
+# QuadInputRelocs: R_PPC64_TOC16_LO_DS 0000000000000010 quadSt
+
+# The powerpc backend doesn't support the quadword load/store instructions yet.
+# So they are tested by linking against an object file assembled with
+# `as -mpower9 -o ppc64le-quadword-ldst.o in.s` and checking the encoding of
+# the unknown instructions in the dissasembly. Source used as input:
+#quads:
+#.Lbegin_quads:
+#.Lgep_quads:
+# addis 2, 12, .TOC.-.Lgep_quads@ha
+# addi 2, 2, .TOC.-.Lgep_quads@l
+#.Llep_quads:
+#.localentry quads, .Llep_quads-.Lgep_quads
+# addis 3, 2, quadLd@toc@ha
+# lq 4, quadLd@toc@l(3)
+# addis 3, 2, quadSt@toc@ha
+# stq 4, quadSt@toc@l(3)
+# blr
+#
+# .p2align 4
+# .global quadLd
+# .lcomm quadLd, 16
+#
+# .global quadSt
+# .lcomm quadSt, 16
+
+
+# e0 82 7f 70 decodes to | 111000 | 00100 | 00010 | 16-bit imm |
+# | 56 | 4 | 2 | 32624 |
+# which is `lq r4, 32624(r2)`
+# f8 82 7f 82 decodes to | 111110 | 00100 | 00010 | 14-bit imm | 10 |
+# | 62 | 4 | 2 | 8160 | 2 |
+# The immediate represents a word offset so this dissasembles to:
+# `stq r4, 32640(r2)`
+# Dis-LABEL: quads:
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: 70 7f 82 e0 <unknown>
+# Dis-NEXT: nop
+# Dis-NEXT: 82 7f 82 f8 <unknown>
+# Dis-NEXT: blr
+
+# e0 83 7f 70 decodes to | 111000 | 00100 | 00011 | 16-bit imm |
+# | 56 | 4 | 3 | 32624 |
+# `lq r4, 32624(r3)`
+# f8 83 7f 82 decodes to | 111110 | 00100 | 00010 | 14-bit imm | 10 |
+# | 62 | 4 | 2 | 8160 | 2 |
+# `stq r4, 32640(r3)`
+# NoOpt-LABEL: quads:
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: 70 7f 83 e0 <unknown>
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: 82 7f 83 f8 <unknown>
+# NoOpt-NEXT: blr
+
diff --git a/test/ELF/ppc64-toc-addis-nop.s b/test/ELF/ppc64-toc-addis-nop.s
new file mode 100644
index 000000000000..a8c850ca2593
--- /dev/null
+++ b/test/ELF/ppc64-toc-addis-nop.s
@@ -0,0 +1,272 @@
+# 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: 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 %t2.so %t.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s
+#
+# RUN: ld.lld --no-toc-optimize %t2.so %t.o -o %t
+# RUN: llvm-objdump -D %t | FileCheck --check-prefix=NoOpt %s
+
+# InputRelocs: Relocation section '.rela.text'
+# InputRelocs: R_PPC64_TOC16_HA
+# InputRelocs: R_PPC64_TOC16_LO
+# InputRelocs: R_PPC64_TOC16_LO_DS
+
+
+ .text
+ .abiversion 2
+
+ .global bytes
+ .p2align 4
+ .type bytes,@function
+bytes:
+.Lbytes_gep:
+ addis 2, 12, .TOC.-.Lbytes_gep@ha
+ addi 2, 2, .TOC.-.Lbytes_gep@l
+.Lbytes_lep:
+ .localentry bytes, .Lbytes_lep-.Lbytes_gep
+ addis 3, 2, byteLd@toc@ha
+ lbz 3, byteLd@toc@l(3)
+ addis 4, 2, byteSt@toc@ha
+ stb 3, byteSt@toc@l(4)
+ blr
+# Dis-LABEL: bytes
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: lbz 3, 32624(2)
+# Dis-NEXT: nop
+# Dis-NEXT: stb 3, 32625(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: bytes
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lbz 3, 32624(3)
+# NoOpt-NEXT: addis 4, 2, 0
+# NoOpt-NEXT: stb 3, 32625(4)
+# NoOpt-NEXT: blr
+
+ .global halfs
+ .p2align 4
+ .type halfs,@function
+halfs:
+.Lhalfs_gep:
+ addis 2, 12, .TOC.-.Lhalfs_gep@ha
+ addi 2, 2, .TOC.-.Lhalfs_gep@l
+.Lhalfs_lep:
+ .localentry halfs, .Lhalfs_lep-.Lhalfs_gep
+ addis 3, 2, halfLd@toc@ha
+ lhz 3, halfLd@toc@l(3)
+ addis 4, 2, halfLd@toc@ha
+ lha 4, halfLd@toc@l(4)
+ addis 5, 2, halfSt@toc@ha
+ sth 4, halfSt@toc@l(5)
+ blr
+# Dis-LABEL: halfs
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: lhz 3, 32626(2)
+# Dis-NEXT: nop
+# Dis-NEXT: lha 4, 32626(2)
+# Dis-NEXT: nop
+# Dis-NEXT: sth 4, 32628(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: halfs
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lhz 3, 32626(3)
+# NoOpt-NEXT: addis 4, 2, 0
+# NoOpt-NEXT: lha 4, 32626(4)
+# NoOpt-NEXT: addis 5, 2, 0
+# NoOpt-NEXT: sth 4, 32628(5)
+# NoOpt-NEXT: blr
+
+
+ .global words
+ .p2align 4
+ .type words,@function
+words:
+.Lwords_gep:
+ addis 2, 12, .TOC.-.Lwords_gep@ha
+ addi 2, 2, .TOC.-.Lwords_gep@l
+.Lwords_lep:
+ .localentry words, .Lwords_lep-.Lwords_gep
+ addis 3, 2, wordLd@toc@ha
+ lwz 3, wordLd@toc@l(3)
+ addis 4, 2, wordLd@toc@ha
+ lwa 4, wordLd@toc@l(4)
+ addis 5, 2, wordSt@toc@ha
+ stw 4, wordSt@toc@l(5)
+ blr
+# Dis-LABEL: words
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: lwz 3, 32632(2)
+# Dis-NEXT: nop
+# Dis-NEXT: lwa 4, 32632(2)
+# Dis-NEXT: nop
+# Dis-NEXT: stw 4, 32636(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: words
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lwz 3, 32632(3)
+# NoOpt-NEXT: addis 4, 2, 0
+# NoOpt-NEXT: lwa 4, 32632(4)
+# NoOpt-NEXT: addis 5, 2, 0
+# NoOpt-NEXT: stw 4, 32636(5)
+# NoOpt-NEXT: blr
+
+ .global doublewords
+ .p2align 4
+ .type doublewords,@function
+doublewords:
+.Ldoublewords_gep:
+ addis 2, 12, .TOC.-.Ldoublewords_gep@ha
+ addi 2, 2, .TOC.-.Ldoublewords_gep@l
+.Ldoublewords_lep:
+ .localentry doublewords, .Ldoublewords_lep-.Ldoublewords_gep
+ addis 3, 2, dwordLd@toc@ha
+ ld 3, dwordLd@toc@l(3)
+ addis 4, 2, dwordSt@toc@ha
+ std 3, dwordSt@toc@l(4)
+ blr
+
+# Dis-LABEL: doublewords
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: ld 3, 32640(2)
+# Dis-NEXT: nop
+# Dis-NEXT: std 3, 32648(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: doublewords
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: ld 3, 32640(3)
+# NoOpt-NEXT: addis 4, 2, 0
+# NoOpt-NEXT: std 3, 32648(4)
+# NoOpt-NEXT: blr
+
+ .global vec_dq
+ .p2align 4
+ .type vec_dq,@function
+vec_dq:
+.Lvec_dq_gep:
+ addis 2, 12, .TOC.-.Lvec_dq_gep@ha
+ addi 2, 2, .TOC.-.Lvec_dq_gep@l
+.Lvec_dq_lep:
+ .localentry vec_dq, .Lvec_dq_lep-.Lvec_dq_gep
+ addis 3, 2, vecLd@toc@ha
+ lxv 3, vecLd@toc@l(3)
+ addis 3, 2, vecSt@toc@ha
+ stxv 3, vecSt@toc@l(3)
+ blr
+
+# Dis-LABEL: vec_dq
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: lxv 3, 32656(2)
+# Dis-NEXT: nop
+# Dis-NEXT: stxv 3, 32672(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: vec_dq
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lxv 3, 32656(3)
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: stxv 3, 32672(3)
+# NoOpt-NEXT: blr
+
+ .global vec_ds
+ .p2align 4
+ .type vec_ds,@function
+vec_ds:
+.Lvec_ds_gep:
+ addis 2, 12, .TOC.-.Lvec_ds_gep@ha
+ addi 2, 2, .TOC.-.Lvec_ds_gep@l
+.Lvec_ds_lep:
+ .localentry vec_ds, .Lvec_dq_lep-.Lvec_dq_gep
+ addis 3, 2, vecLd@toc@ha
+ lxsd 3, vecLd@toc@l(3)
+ addis 3, 2, vecSt@toc@ha
+ stxsd 3, vecSt@toc@l(3)
+ addis 3, 2, vecLd@toc@ha
+ lxssp 3, vecLd@toc@l(3)
+ addis 3, 2, vecSt@toc@ha
+ stxssp 3, vecSt@toc@l(3)
+ blr
+# Dis-LABEL: vec_ds
+# Dis-NEXT: addis
+# Dis-NEXT: addi
+# Dis-NEXT: nop
+# Dis-NEXT: lxsd 3, 32656(2)
+# Dis-NEXT: nop
+# Dis-NEXT: stxsd 3, 32672(2)
+# Dis-NEXT: nop
+# Dis-NEXT: lxssp 3, 32656(2)
+# Dis-NEXT: nop
+# Dis-NEXT: stxssp 3, 32672(2)
+# Dis-NEXT: blr
+
+# NoOpt-LABEL: vec_ds
+# NoOpt-NEXT: addis
+# NoOpt-NEXT: addi
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lxsd 3, 32656(3)
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: stxsd 3, 32672(3)
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: lxssp 3, 32656(3)
+# NoOpt-NEXT: addis 3, 2, 0
+# NoOpt-NEXT: stxssp 3, 32672(3)
+# NoOpt-NEXT: blr
+
+
+ .global byteLd
+ .lcomm byteLd, 1, 1
+
+ .global byteSt
+ .lcomm byteSt, 1, 1
+
+ .global halfLd
+ .lcomm halfLd, 2, 2
+
+ .global halfSt
+ .lcomm halfSt, 2, 2
+
+ .global wordLd
+ .lcomm wordLd, 4, 4
+
+ .global wordSt
+ .lcomm wordSt, 4, 4
+
+ .global dwordLd
+ .lcomm dwordLd, 8, 8
+
+ .global dwordSt
+ .lcomm dwordSt, 8, 8
+
+ .global vecLd
+ .lcomm vecLd, 16, 16
+
+ .global vecSt
+ .lcomm vecSt, 16, 16
diff --git a/test/ELF/ppc64-toc-rel.s b/test/ELF/ppc64-toc-rel.s
index ac156c78b3a4..5769e43fbb91 100644
--- a/test/ELF/ppc64-toc-rel.s
+++ b/test/ELF/ppc64-toc-rel.s
@@ -1,13 +1,15 @@
# 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: 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
+# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-LE %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
# 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
@@ -45,15 +47,15 @@ _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-LE: Relocations [
+# RELOCS-LE-NEXT: .rela.text {
+# RELOCS-LE: 0x8 R_PPC64_TOC16_HA global_a 0x0
+# RELOCS-LE: 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
+# RELOCS-BE: 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
@@ -70,19 +72,9 @@ _start:
# 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-LE: Disassembly of section .got:
+# CHECK-LE-NEXT: .got:
+# CHECK-LE-NEXT: 10030000: 00 80 03 10
# CHECK-BE: Disassembly of section .got:
# CHECK-BE-NEXT: .got:
diff --git a/test/ELF/ppc64-toc-restore-recursive-call.s b/test/ELF/ppc64-toc-restore-recursive-call.s
new file mode 100644
index 000000000000..4bedcfecf383
--- /dev/null
+++ b/test/ELF/ppc64-toc-restore-recursive-call.s
@@ -0,0 +1,52 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t1.o
+# RUN: ld.lld -shared %t1.o -o %t
+# RUN: llvm-objdump -d -r %t | FileCheck %s
+
+# For a recursive call that is interposable the linker calls the plt-stub rather
+# then calling the function directly. Since the call is through a plt stub and
+# might be interposed with a different definition at runtime, a toc-restore is
+# required to follow the call.
+
+# The decision to use a plt-stub for the recursive call is not one I feel
+# strongly about either way. It was done because it matches what bfd and gold do
+# for recursive calls as well as keeps the logic for recursive calls consistent
+# with non-recursive calls.
+
+# CHECK-LABEL: __plt_recursive_func:
+# CHECK-NEXT: 10000:
+# CHECK-LABEL: recursive_func
+# CHECK-NEXT: 10014:
+# CHECK: 1003c: {{[0-9a-fA-F ]+}} bl .+67108804
+# CHECK-NEXT: ld 2, 24(1)
+
+ .abiversion 2
+ .section ".text"
+ .p2align 2
+ .global recursive_func
+ .type recursive_func, @function
+recursive_func:
+.Lrf_gep:
+ addis 2, 12, .TOC.-.Lrf_gep@ha
+ addi 2, 2, .TOC.-.Lrf_gep@l
+ .localentry recursive_func, .-recursive_func
+ cmpldi 3, 2
+ blt 0, .Lend
+
+ mflr 0
+ std 0, 16(1)
+ stdu 1, -32(1)
+ addi 5, 3, -1
+ mulld 4, 4, 3
+ mr 3, 5
+ bl recursive_func
+ nop
+ mr 4, 3
+ addi 1, 1, 32
+ ld 0, 16(1)
+ mtlr 0
+
+.Lend:
+ extsw 3, 4
+ blr
diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s
index 9efe0e81f5e5..d9e06ca6e596 100644
--- a/test/ELF/ppc64-toc-restore.s
+++ b/test/ELF/ppc64-toc-restore.s
@@ -22,7 +22,7 @@ bar_local:
blr
# Calling external function foo in a shared object needs a nop.
-# Calling local function bar_local doe snot need a nop.
+# Calling local function bar_local doe not need a nop.
.global _start
_start:
bl foo
diff --git a/test/ELF/ppc64-tocopt-option.s b/test/ELF/ppc64-tocopt-option.s
new file mode 100644
index 000000000000..78494346beb5
--- /dev/null
+++ b/test/ELF/ppc64-tocopt-option.s
@@ -0,0 +1,14 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+# RUN: not ld.lld %t --toc-optimize -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: error: --toc-optimize is only supported on the PowerPC64 target
+
+ .global __start
+ .type __start,@function
+
+ .text
+ .quad 0
+ __start:
+
diff --git a/test/ELF/pr34660.s b/test/ELF/pr34660.s
index 53998ad0f728..9509b4e9d984 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-readelf %t -t | FileCheck %s --check-prefix=SYM
+# RUN: llvm-readelf %t --symbols | 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/progname.s b/test/ELF/progname.s
index ecd0fd872347..228e3f61e67a 100644
--- a/test/ELF/progname.s
+++ b/test/ELF/progname.s
@@ -17,7 +17,7 @@
// RUN: ld.lld -dynamic-list %t.dynlist -o %t %t.o %t.so
// RUN: llvm-readobj -dyn-symbols %t | FileCheck %s
-// CHECK: Name: __progname@
+// CHECK: Name: __progname
// CHECK-NEXT: Value: 0x201000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/protected-shared.s b/test/ELF/protected-shared.s
index e69b10899dae..3501162e6153 100644
--- a/test/ELF/protected-shared.s
+++ b/test/ELF/protected-shared.s
@@ -32,7 +32,7 @@ bar:
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local (0x0)
@@ -41,7 +41,7 @@ bar:
// CHECK-NEXT: Section: Undefined (0x0)
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: foo@
+// CHECK-NEXT: Name: foo
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
diff --git a/test/ELF/push-state.s b/test/ELF/push-state.s
index 5a01cd2eeedd..f3d55c3488b3 100644
--- a/test/ELF/push-state.s
+++ b/test/ELF/push-state.s
@@ -32,5 +32,8 @@
// 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
+// RUN: not ld.lld -o %t.exe -pop-state %t.a %t1.o -M 2>&1 | FileCheck -check-prefix=ERR %s
+// ERR: error: unbalanced --push-state/--pop-state
+
.globl _start
_start:
diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s
index 83190a270048..d65ea275413c 100644
--- a/test/ELF/relative-dynamic-reloc-ppc64.s
+++ b/test/ELF/relative-dynamic-reloc-ppc64.s
@@ -32,7 +32,7 @@
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
@@ -41,7 +41,7 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: external@
+// CHECK-NEXT: Name: external
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
diff --git a/test/ELF/relative-dynamic-reloc.s b/test/ELF/relative-dynamic-reloc.s
index 0ed7e40f7436..24d03f28a43b 100644
--- a/test/ELF/relative-dynamic-reloc.s
+++ b/test/ELF/relative-dynamic-reloc.s
@@ -28,7 +28,7 @@
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
@@ -37,7 +37,7 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: external@
+// CHECK-NEXT: Name: external
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
diff --git a/test/ELF/relocatable-bss.s b/test/ELF/relocatable-bss.s
index becfbaed62df..716eb4abf2f6 100644
--- a/test/ELF/relocatable-bss.s
+++ b/test/ELF/relocatable-bss.s
@@ -20,7 +20,7 @@
# CHECK-NEXT: Version:
# CHECK-NEXT: Entry:
# CHECK-NEXT: ProgramHeaderOffset:
-# CHECK-NEXT: SectionHeaderOffset: 0xD8
+# CHECK-NEXT: SectionHeaderOffset: 0xE8
# CHECK-NEXT: Flags [
# CHECK-NEXT: ]
# CHECK-NEXT: HeaderSize:
diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s
index bb7a78490fdd..6a8d83357cf0 100644
--- a/test/ELF/relocatable-comdat-multiple.s
+++ b/test/ELF/relocatable-comdat-multiple.s
@@ -8,7 +8,7 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Link: 8
+# CHECK-NEXT: Link: 9
# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: aaa
@@ -20,7 +20,7 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 5
-# CHECK-NEXT: Link: 8
+# CHECK-NEXT: Link: 9
# CHECK-NEXT: Info: 6
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bbb
diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s
index 11aa30c7e6bd..98ef993d5d0d 100644
--- a/test/ELF/relocatable-comdat.s
+++ b/test/ELF/relocatable-comdat.s
@@ -30,7 +30,7 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Link: 5
+# CHECK-NEXT: Link: 6
# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: abc
diff --git a/test/ELF/relocatable-comdat2.s b/test/ELF/relocatable-comdat2.s
index 27844feae16e..3318fb6f10be 100644
--- a/test/ELF/relocatable-comdat2.s
+++ b/test/ELF/relocatable-comdat2.s
@@ -13,7 +13,7 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 2
-# CHECK-NEXT: Link: 7
+# CHECK-NEXT: Link: 8
# CHECK-NEXT: Info: 1
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: bar
@@ -24,7 +24,7 @@
# CHECK-NEXT: Group {
# CHECK-NEXT: Name: .group
# CHECK-NEXT: Index: 4
-# CHECK-NEXT: Link: 7
+# CHECK-NEXT: Link: 8
# CHECK-NEXT: Info: 2
# CHECK-NEXT: Type: COMDAT
# CHECK-NEXT: Signature: zed
diff --git a/test/ELF/relocatable-compressed-input.s b/test/ELF/relocatable-compressed-input.s
index 47d8c111452d..7ef0cf0b051b 100644
--- a/test/ELF/relocatable-compressed-input.s
+++ b/test/ELF/relocatable-compressed-input.s
@@ -7,7 +7,7 @@
# RUN: ld.lld %t1 -o %t2 -r
# RUN: llvm-readobj -sections -section-data %t2 | FileCheck %s
-## Check we decompress section and remove ".z" prefix specific for zlib-gnu compression.
+## Check we uncompress section and remove ".z" prefix specific for zlib-gnu compression.
# CHECK: Section {
# CHECK: Index:
# CHECK: Name: .debug_str
diff --git a/test/ELF/relocatable-many-sections.s b/test/ELF/relocatable-many-sections.s
index 347f3f784f26..0d84c6bd78ba 100644
--- a/test/ELF/relocatable-many-sections.s
+++ b/test/ELF/relocatable-many-sections.s
@@ -9,8 +9,8 @@
## sections amount is greater than SHN_LORESERVE.
# RUN: llvm-readobj -file-headers %t | FileCheck %s --check-prefix=HDR
# HDR: ElfHeader {
-# HDR: SectionHeaderCount: 0 (65543)
-# HDR-NEXT: StringTableSectionIndex: 65535 (65541)
+# HDR: SectionHeaderCount: 0 (65544)
+# HDR-NEXT: StringTableSectionIndex: 65535 (65542)
## Check that:
## 1) 65541 is the index of .shstrtab section.
@@ -18,13 +18,15 @@
## 3) .symtab_shndxr entry size and alignment == 4.
## 4) .symtab_shndxr has size equal to
## (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndxr) = 0x4 * 0x180048 / 0x18 == 0x04000c
+
# RUN: llvm-readelf -sections -symbols %t | FileCheck %s
-## [Nr] Name Type Address Off Size ES Flg Lk Inf Al
-# CHECK: [65538] .bar
-# CHECK-NEXT: [65539] .symtab SYMTAB 0000000000000000 000040 180078 18 65542 65539 8
-# CHECK-NEXT: [65540] .symtab_shndxr SYMTAB SECTION INDICES 0000000000000000 1800b8 040014 04 65539 0 4
-# CHECK-NEXT: [65541] .shstrtab STRTAB 0000000000000000 1c00cc 0f0035 00 0 0 1
-# CHECK-NEXT: [65542] .strtab STRTAB 0000000000000000 2b0101 00000c 00
+# [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# CHECK: [65539] .note.GNU-stack PROGBITS 0000000000000000 000040 000000 00 0 0 1
+# CHECK: [65540] .symtab SYMTAB 0000000000000000 000040 180078 18 65543 65539 8
+# CHECK: [65541] .symtab_shndxr SYMTAB SECTION INDICES 0000000000000000 1800b8 040014 04 65540 0 4
+# CHECK: [65542] .shstrtab STRTAB 0000000000000000 1c00cc 0f0045 00 0 0 1
+# CHECK: [65543] .strtab STRTAB 0000000000000000 2b0111 00000c 00 0 0 1
+
# 5) Check we are able to represent symbol foo with section (.bar) index > 0xFF00 (SHN_LORESERVE).
# CHECK: GLOBAL DEFAULT 65538 foo
diff --git a/test/ELF/relocatable-rel-iplt.s b/test/ELF/relocatable-rel-iplt.s
new file mode 100644
index 000000000000..773a09f52815
--- /dev/null
+++ b/test/ELF/relocatable-rel-iplt.s
@@ -0,0 +1,56 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=i686-- %s -o %t1.o
+# RUN: ld.lld -r %t1.o -o %t2.o
+# RUN: llvm-readobj -t %t2.o | FileCheck %s
+
+// CHECK: Symbols [
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: (0)
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local (0x0)
+// CHECK-NEXT: Type: None (0x0)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined (0x0)
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: (0)
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local (0x0)
+// CHECK-NEXT: Type: Section (0x3)
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text (0x1)
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: __rel_iplt_end (1)
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Weak (0x2)
+// CHECK-NEXT: Type: None (0x0)
+// CHECK-NEXT: Other [ (0x2)
+// CHECK-NEXT: STV_HIDDEN (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Section: Undefined (0x0)
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: __rel_iplt_start (16)
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Weak (0x2)
+// CHECK-NEXT: Type: None (0x0)
+// CHECK-NEXT: Other [ (0x2)
+// CHECK-NEXT: STV_HIDDEN (0x2)
+// CHECK-NEXT: ]
+// CHECK-NEXT: Section: Undefined (0x0)
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+
+ movl __rel_iplt_start, %eax
+ movl __rel_iplt_end, %eax
+ ret
+
+ .hidden __rel_iplt_start
+ .hidden __rel_iplt_end
+ .weak __rel_iplt_start
+ .weak __rel_iplt_end
diff --git a/test/ELF/relocatable.s b/test/ELF/relocatable.s
index 7cb2a084c935..7235ea03c288 100644
--- a/test/ELF/relocatable.s
+++ b/test/ELF/relocatable.s
@@ -4,6 +4,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocatable2.s -o %t3.o
# RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t
# RUN: llvm-readobj -file-headers -sections -program-headers -symbols -r %t | FileCheck %s
+# RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=SECTION %s
# RUN: llvm-objdump -s -d %t | FileCheck -check-prefix=CHECKTEXT %s
## Test --relocatable alias
@@ -37,8 +38,8 @@
# CHECK-NEXT: ProgramHeaderEntrySize: 0
# CHECK-NEXT: ProgramHeaderCount: 0
# CHECK-NEXT: SectionHeaderEntrySize: 64
-# CHECK-NEXT: SectionHeaderCount: 7
-# CHECK-NEXT: StringTableSectionIndex: 5
+# CHECK-NEXT: SectionHeaderCount: 8
+# CHECK-NEXT: StringTableSectionIndex: 6
# CHECK-NEXT: }
# CHECK: Relocations [
@@ -51,6 +52,17 @@
# CHECK-NEXT: 0x4E R_X86_64_32S yyy 0x0
# CHECK-NEXT: }
+# SECTION: Sections:
+# SECTION: Idx Name Size Address Type
+# SECTION: 0 00000000 0000000000000000
+# SECTION: 1 .text 00000056 0000000000000000 TEXT
+# SECTION: 2 .rela.text 00000090 0000000000000000
+# SECTION: 3 .bss 00000018 0000000000000000 BSS
+# SECTION: 4 .note.GNU-stack 00000000 0000000000000000
+# SECTION: 5 .symtab 00000168 0000000000000000
+# SECTION: 6 .shstrtab 00000041 0000000000000000
+# SECTION: 7 .strtab 0000002d 0000000000000000
+
# CHECKTEXT: Disassembly of section .text:
# CHECKTEXT-NEXT: main:
# CHECKTEXT-NEXT: 0: c7 04 25 00 00 00 00 05 00 00 00 movl $5, 0
diff --git a/test/ELF/relocation-b-aarch64.test b/test/ELF/relocation-b-aarch64.test
index 24bf4b74ef92..152cc39d8ac3 100644
--- a/test/ELF/relocation-b-aarch64.test
+++ b/test/ELF/relocation-b-aarch64.test
@@ -9,9 +9,9 @@
# CHECK: Disassembly of section .text:
# CHECK-NEXT: foo:
-# CHECK-NEXT: 20000: 01 00 00 14 b #4
+# CHECK-NEXT: 210000: 01 00 00 14 b #4
# CHECK: bar:
-# CHECK-NEXT: 20004: ff ff ff 17 b #-4
+# CHECK-NEXT: 210004: ff ff ff 17 b #-4
!ELF
FileHeader:
diff --git a/test/ELF/relocation-before-merge-start.s b/test/ELF/relocation-before-merge-start.s
new file mode 100644
index 000000000000..3550fd2efa65
--- /dev/null
+++ b/test/ELF/relocation-before-merge-start.s
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
+// CHECK: relocation-before-merge-start.s.tmp.o:(.foo): offset is outside the section
+
+.data
+.long .foo - 1
+.section .foo,"aM",@progbits,4
+.quad 0
diff --git a/test/ELF/relocation-common.s b/test/ELF/relocation-common.s
index 71b1ac0e2e24..392c495b1f17 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
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-objdump -t -d %t | FileCheck %s
.global _start
_start:
@@ -10,5 +10,5 @@ _start:
.global sym1
.comm sym1,4,4
-// CHECK: 201000: {{.*}} movl $1, 4086(%rip)
-// CHECK: 0000000000202000 g .bss 00000004 sym1
+# CHECK: 201000: {{.*}} movl $1, 4086(%rip)
+# CHECK: 0000000000202000 g O .bss 00000004 sym1
diff --git a/test/ELF/relocation-copy-i686.s b/test/ELF/relocation-copy-i686.s
index f9ee32e2b35e..8b14f9aadde6 100644
--- a/test/ELF/relocation-copy-i686.s
+++ b/test/ELF/relocation-copy-i686.s
@@ -21,7 +21,7 @@ movl $9, z
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_WRITE
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x13000
+// CHECK-NEXT: Address: 0x403000
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size: 24
// CHECK-NEXT: Link: 0
@@ -52,12 +52,12 @@ movl $9, z
// CHECK-NEXT: }
// CHECK-NEXT: ]
-// 77824 = 0x13000
+// 4206592 = 0x403000
// 16 is alignment here
-// 77840 = 0x13000 + 16
-// 77844 = 0x13000 + 16 + 4
+// 4206608 = 0x403000 + 16
+// 4206612 = 0x403000 + 16 + 4
// CODE: Disassembly of section .text:
// CODE-NEXT: main:
-// CODE-NEXT: 11000: c7 05 00 30 01 00 05 00 00 00 movl $5, 77824
-// CODE-NEXT: 1100a: c7 05 10 30 01 00 07 00 00 00 movl $7, 77840
-// CODE-NEXT: 11014: c7 05 14 30 01 00 09 00 00 00 movl $9, 77844
+// CODE-NEXT: 401000: c7 05 00 30 40 00 05 00 00 00 movl $5, 4206592
+// CODE-NEXT: 40100a: c7 05 10 30 40 00 07 00 00 00 movl $7, 4206608
+// CODE-NEXT: 401014: c7 05 14 30 40 00 09 00 00 00 movl $9, 4206612
diff --git a/test/ELF/relocation-i686.s b/test/ELF/relocation-i686.s
index fdec7caa33be..6ca487c0ab11 100644
--- a/test/ELF/relocation-i686.s
+++ b/test/ELF/relocation-i686.s
@@ -27,14 +27,14 @@ R_386_PC32_2:
// CHECK: Disassembly of section .R_386_32:
// CHECK-NEXT: R_386_32:
-// CHECK-NEXT: 11000: {{.*}} movl $69633, %edx
+// CHECK-NEXT: 401000: {{.*}} movl $4198401, %edx
// CHECK: Disassembly of section .R_386_PC32:
// CHECK-NEXT: R_386_PC32:
-// CHECK-NEXT: 11005: e8 04 00 00 00 calll 4
+// CHECK-NEXT: 401005: e8 04 00 00 00 calll 4
// CHECK: R_386_PC32_2:
-// CHECK-NEXT: 1100e: 90 nop
+// CHECK-NEXT: 40100e: 90 nop
// Create a .got
movl bar@GOT, %eax
@@ -45,7 +45,7 @@ movl bar@GOT, %eax
// ADDR-NEXT: SHF_ALLOC
// ADDR-NEXT: SHF_EXECINSTR
// ADDR-NEXT: ]
-// ADDR-NEXT: Address: 0x11040
+// ADDR-NEXT: Address: 0x401040
// ADDR-NEXT: Offset: 0x1040
// ADDR-NEXT: Size: 32
@@ -55,7 +55,7 @@ movl bar@GOT, %eax
// ADDR-NEXT: SHF_ALLOC
// ADDR-NEXT: SHF_WRITE
// ADDR-NEXT: ]
-// ADDR-NEXT: Address: 0x13078
+// ADDR-NEXT: Address: 0x403078
// ADDR-NEXT: Offset:
// ADDR-NEXT: Size: 8
@@ -63,18 +63,18 @@ movl bar@GOT, %eax
R_386_GOTPC:
movl $_GLOBAL_OFFSET_TABLE_, %eax
-// 0x12078 + 8 - 0x11014 = 4204
+// 0x402078 + 8 - 0x401014 = 4204
// CHECK: Disassembly of section .R_386_GOTPC:
// CHECK-NEXT: R_386_GOTPC:
-// CHECK-NEXT: 11014: {{.*}} movl $8300, %eax
+// CHECK-NEXT: 401014: {{.*}} movl $8300, %eax
.section .dynamic_reloc, "ax",@progbits
call bar
-// addr(.plt) + 16 - (0x11019 + 5) = 50
+// addr(.plt) + 16 - (0x401019 + 5) = 50
// CHECK: Disassembly of section .dynamic_reloc:
// CHECK-NEXT: .dynamic_reloc:
-// CHECK-NEXT: 11019: e8 32 00 00 00 calll 50
+// CHECK-NEXT: 401019: e8 32 00 00 00 calll 50
.section .R_386_GOT32,"ax",@progbits
.global R_386_GOT32
@@ -84,13 +84,13 @@ R_386_GOT32:
movl bar+8@GOT, %eax
movl zed+4@GOT, %eax
-// 4294967288 = 0xFFFFFFF8 = got[0](0x12070) - .got(0x12070) - sizeof(.got)(8)
-// 4294967292 = 0xFFFFFFFC = got[1](0x12074) - .got(0x12070) - sizeof(.got)(8)
+// 4294967288 = 0xFFFFFFF8 = got[0](0x402070) - .got(0x402070) - sizeof(.got)(8)
+// 4294967292 = 0xFFFFFFFC = got[1](0x402074) - .got(0x402070) - sizeof(.got)(8)
// 0xFFFFFFF8 + 8 = 0
// 0xFFFFFFFC + 4 = 0
// CHECK: Disassembly of section .R_386_GOT32:
// CHECK-NEXT: R_386_GOT32:
-// CHECK-NEXT: 1101e: a1 f8 ff ff ff movl 4294967288, %eax
-// CHECK-NEXT: 11023: a1 fc ff ff ff movl 4294967292, %eax
-// CHECK-NEXT: 11028: a1 00 00 00 00 movl 0, %eax
-// CHECK-NEXT: 1102d: a1 00 00 00 00 movl 0, %eax
+// CHECK-NEXT: 40101e: a1 f8 ff ff ff movl 4294967288, %eax
+// CHECK-NEXT: 401023: a1 fc ff ff ff movl 4294967292, %eax
+// CHECK-NEXT: 401028: a1 00 00 00 00 movl 0, %eax
+// CHECK-NEXT: 40102d: a1 00 00 00 00 movl 0, %eax
diff --git a/test/ELF/relocation-past-merge-end.s b/test/ELF/relocation-past-merge-end.s
index a3e7b59a415a..53015bc9013d 100644
--- a/test/ELF/relocation-past-merge-end.s
+++ b/test/ELF/relocation-past-merge-end.s
@@ -1,7 +1,7 @@
// REQUIRES: x86
// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
-// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): entry is past the end of the section
+// CHECK: relocation-past-merge-end.s.tmp.o:(.foo): offset is outside the section
.data
.long .foo + 10
diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s
index f60f0929e705..1aa2222d9494 100644
--- a/test/ELF/relocation-size-shared.s
+++ b/test/ELF/relocation-size-shared.s
@@ -28,20 +28,7 @@
// DISASM-NEXT: 20100c: 00 00
// DISASM-NEXT: 20100e: 00 00
// DISASM-NEXT: 201010: 1b 00
-// DISASM-NEXT: 201012: 00 00
-// DISASM-NEXT: 201014: 00 00
-// DISASM-NEXT: 201016: 00 00
-// DISASM-NEXT: 201018: 00 00
-// DISASM-NEXT: 20101a: 00 00
-// DISASM-NEXT: 20101c: 00 00
-// DISASM-NEXT: 20101e: 00 00
-// DISASM-NEXT: 201020: 00 00
-// DISASM-NEXT: 201022: 00 00
-// DISASM-NEXT: 201024: 00 00
-// DISASM-NEXT: 201026: 00 00
-// DISASM-NEXT: 201028: 00 00
-// DISASM-NEXT: 20102a: 00 00
-// DISASM-NEXT: 20102c: 00 00
+// DISASM-NEXT: ...
// DISASM-NEXT: 20102e: 00 00
// DISASM: _start:
// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax
diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s
index 525b1e1d1331..c2554a4e4fc1 100644
--- a/test/ELF/relocation-size.s
+++ b/test/ELF/relocation-size.s
@@ -57,18 +57,7 @@
// DISASMSHARED: Disassembly of section test:
// DISASMSHARED-NEXT: _data:
-// DISASMSHARED-NEXT: 1000: 00 00
-// DISASMSHARED-NEXT: 1002: 00 00
-// DISASMSHARED-NEXT: 1004: 00 00
-// DISASMSHARED-NEXT: 1006: 00 00
-// DISASMSHARED-NEXT: 1008: 00 00
-// DISASMSHARED-NEXT: 100a: 00 00
-// DISASMSHARED-NEXT: 100c: 00 00
-// DISASMSHARED-NEXT: 100e: 00 00
-// DISASMSHARED-NEXT: 1010: 00 00
-// DISASMSHARED-NEXT: 1012: 00 00
-// DISASMSHARED-NEXT: 1014: 00 00
-// DISASMSHARED-NEXT: 1016: 00 00
+// DISASMSHARED-NEXT: ...
// DISASMSHARED-NEXT: 1018: 19 00
// DISASMSHARED-NEXT: 101a: 00 00
// DISASMSHARED-NEXT: 101c: 00 00
diff --git a/test/ELF/reproduce-backslash.s b/test/ELF/reproduce-backslash.s
index 7a9964db62aa..39e63ccc121e 100644
--- a/test/ELF/reproduce-backslash.s
+++ b/test/ELF/reproduce-backslash.s
@@ -6,4 +6,4 @@
# 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
+# CHECK: repro/{{.*}}/foo\{{[\]?}}.o
diff --git a/test/ELF/retain-symbols-file.s b/test/ELF/retain-symbols-file.s
index 79d569d69cdb..0ab19774b534 100644
--- a/test/ELF/retain-symbols-file.s
+++ b/test/ELF/retain-symbols-file.s
@@ -11,7 +11,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value:
# CHECK-NEXT: Size:
# CHECK-NEXT: Binding:
diff --git a/test/ELF/riscv-branch.test b/test/ELF/riscv-branch.test
new file mode 100644
index 000000000000..3af9364c5028
--- /dev/null
+++ b/test/ELF/riscv-branch.test
@@ -0,0 +1,119 @@
+# .option norelax
+# .global _start
+# _start:
+# beq x0, x0, _start
+#
+# .section .reloc_max, "ax", @progbits
+# L1:
+# beq x0, x0, L1 + 0xffe
+#
+# .section .reloc_min, "ax", @progbits
+# L2:
+# beq x0, x0, L2 - 0x1000
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# CHECK: - Name: .text
+# CHECK: Content: '63000000'
+# 11000: 00000063 beqz zero,11000 <_start>
+#
+# CHECK: - Name: .reloc_max
+# CHECK: Content: E30F007E
+# 11004: 7e000fe3 beqz zero,12002
+#
+# CHECK: - Name: .reloc_min
+# CHECK: Content: '63000080'
+# 11008: 80000063 beqz zero,10008
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: '63000000'
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _start
+ Type: R_RISCV_BRANCH
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ - Name: .reloc_max
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: E30F007E
+ - Name: .rela.reloc_max
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_max
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L1
+ Type: R_RISCV_BRANCH
+ Addend: 4094
+ - Name: .reloc_min
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: '63000080'
+ - Name: .rela.reloc_min
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_min
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L2
+ Type: R_RISCV_BRANCH
+ Addend: -4096
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reloc_max
+ Type: STT_SECTION
+ Section: .reloc_max
+ - Name: L1
+ Section: .reloc_max
+ - Name: .reloc_min
+ Type: STT_SECTION
+ Section: .reloc_min
+ - Name: L2
+ Section: .reloc_min
+ Global:
+ - Name: _start
+ Section: .text
+...
diff --git a/test/ELF/riscv-call.test b/test/ELF/riscv-call.test
new file mode 100644
index 000000000000..d8077d480378
--- /dev/null
+++ b/test/ELF/riscv-call.test
@@ -0,0 +1,95 @@
+# .option norelax
+# .global _start
+# _start:
+# call _start + 4
+#
+# .section .reloc_neg, "ax", @progbits
+# L1:
+# call L1 - 4
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# CHECK: - Name: .text
+# CHECK: Content: '97000000E7804000'
+#
+# 11000: 00000097 auipc ra,0x0
+# 11004: 004080e7 jalr 4(ra)
+#
+# CHECK: - Name: .reloc_neg
+# CHECK: Content: 97000000E780C0FF
+#
+# 11008: 00000097 auipc ra,0x0
+# 1100c: ffc080e7 jalr -4(ra)
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: '97000000E7800000'
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _start
+ Type: R_RISCV_CALL
+ Addend: 4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ - Name: .reloc_neg
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: '97000000E7800000'
+ - Name: .rela.reloc_neg
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_neg
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L1
+ Type: R_RISCV_CALL
+ Addend: -4
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reloc_neg
+ Type: STT_SECTION
+ Section: .reloc_neg
+ - Name: L1
+ Section: .reloc_neg
+ Global:
+ - Name: _start
+ Section: .text
+...
diff --git a/test/ELF/riscv-hi20-lo12.test b/test/ELF/riscv-hi20-lo12.test
new file mode 100644
index 000000000000..8d21d334dfa1
--- /dev/null
+++ b/test/ELF/riscv-hi20-lo12.test
@@ -0,0 +1,86 @@
+# .option norelax
+# .global _start
+#
+# .section .reloc_12345678, "ax", @progbits
+# _start:
+# foo = 0x12345678
+# lui a0, %hi(foo)
+# addi a0, a0, %lo(foo)
+# lw a0, %lo(foo)(a0)
+#
+# .section .reloc_fedcba98, "ax", @progbits
+# foo = 0xfedcba98
+# lui a0, %hi(foo)
+# addi a0, a0, %lo(foo)
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# CHECK: - Name: .reloc_12345678
+# CHECK: Content: '375534121305856703258567'
+# 11000: 12345537 lui a0,0x12345
+# 11004: 67850513 addi a0,a0,1656 # 12345678 <__global_pointer$+0x12332e78>
+# 11008: 67852503 lw a0,1656(a0)
+#
+# CHECK: - Name: .reloc_fedcba98
+# CHECK: Content: 37C5DCFE130585A9
+# 1100c: fedcc537 lui a0,0xfedcc
+# 11010: a9850513 addi a0,a0,-1384 # fedcba98 <__global_pointer$+0xfedb9298>
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ - Name: .reloc_12345678
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: '375534121305856703258567'
+ - Name: .reloc_fedcba98
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: 37C5DCFE130585A9
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reloc_12345678
+ Type: STT_SECTION
+ Section: .reloc_12345678
+ - Name: foo
+ Value: 0x00000000FEDCBA98
+ - Name: .reloc_fedcba98
+ Type: STT_SECTION
+ Section: .reloc_fedcba98
+ Global:
+ - Name: _start
+ Section: .reloc_12345678
+...
diff --git a/test/ELF/riscv-jal-error.test b/test/ELF/riscv-jal-error.test
new file mode 100644
index 000000000000..9df95c9cc4ea
--- /dev/null
+++ b/test/ELF/riscv-jal-error.test
@@ -0,0 +1,93 @@
+# .option norelax
+# .global _start
+#
+# _start:
+# L1:
+# jal x0, L1 + 0x100000
+# L2:
+# jal x0, L2 - 0x100002
+# L3:
+# jal x0, L3 + 1
+# L4:
+# c.jal L4 + 1
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s
+#
+# CHECK: {{.*}}(.text+0x0): relocation R_RISCV_JAL out of range
+# CHECK: {{.*}}(.text+0x4): relocation R_RISCV_JAL out of range
+# CHECK: {{.*}}(.text+0x8): improper alignment for relocation R_RISCV_JAL
+# CHECK: {{.*}}(.text+0xC): improper alignment for relocation R_RISCV_RVC_JUMP
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: 6F0000806FF0FF7F6F0000000120
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L1
+ Type: R_RISCV_JAL
+ Addend: 1048576
+ - Offset: 0x0000000000000004
+ Symbol: L2
+ Type: R_RISCV_JAL
+ Addend: -1048578
+ - Offset: 0x0000000000000008
+ Symbol: L3
+ Type: R_RISCV_JAL
+ Addend: 1
+ - Offset: 0x000000000000000C
+ Symbol: L4
+ Type: R_RISCV_RVC_JUMP
+ Addend: 1
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: L1
+ Section: .text
+ - Name: L2
+ Section: .text
+ Value: 0x0000000000000004
+ - Name: L3
+ Section: .text
+ Value: 0x0000000000000008
+ - Name: L4
+ Section: .text
+ Value: 0x000000000000000C
+ Global:
+ - Name: _start
+ Section: .text
+...
diff --git a/test/ELF/riscv-jal.test b/test/ELF/riscv-jal.test
new file mode 100644
index 000000000000..cb40dc6db124
--- /dev/null
+++ b/test/ELF/riscv-jal.test
@@ -0,0 +1,161 @@
+# .option norelax
+# .global _start
+#
+# .section .reloc_zero, "ax", @progbits
+# _start:
+# L1:
+# jal x0, L1
+# L2:
+# c.jal L2
+#
+# .section .reloc_max, "ax", @progbits
+# L3:
+# jal x0, L3 + 0xffffe
+# L4:
+# c.jal L4 + 0x7fe
+#
+# .section .reloc_min, "ax", @progbits
+# L5:
+# jal x0, L5 - 0x100000
+# L6:
+# c.jal L6 - 0x800
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# CHECK: - Name: .reloc_zero
+# CHECK: Content: 6F0000000120
+# 11000: 0000006f j 11000
+# 11004: 2001 jal 11004
+#
+# CHECK: - Name: .reloc_max
+# CHECK: Content: 6FF0FF7FFD2F
+# 11006: 7ffff06f j 111004
+# 1100a: 2ffd jal 11808
+#
+# CHECK: - Name: .reloc_min
+# CHECK: Content: 6F0000800130
+# 1100c: 8000006f j fff1100c
+# 11010: 3001 jal 10810
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: ''
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ - Name: .reloc_zero
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: 6F0000000120
+ - Name: .rela.reloc_zero
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_zero
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L1
+ Type: R_RISCV_JAL
+ - Offset: 0x0000000000000004
+ Symbol: L2
+ Type: R_RISCV_RVC_JUMP
+ - Name: .reloc_max
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: 6FF0FF7FFD2F
+ - Name: .rela.reloc_max
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_max
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L3
+ Type: R_RISCV_JAL
+ Addend: 1048574
+ - Offset: 0x0000000000000004
+ Symbol: L4
+ Type: R_RISCV_RVC_JUMP
+ Addend: 2046
+ - Name: .reloc_min
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: 6F0000800130
+ - Name: .rela.reloc_min
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_min
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L5
+ Type: R_RISCV_JAL
+ Addend: -1048576
+ - Offset: 0x0000000000000004
+ Symbol: L6
+ Type: R_RISCV_RVC_JUMP
+ Addend: -2048
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reloc_zero
+ Type: STT_SECTION
+ Section: .reloc_zero
+ - Name: L1
+ Section: .reloc_zero
+ - Name: L2
+ Section: .reloc_zero
+ Value: 0x0000000000000004
+ - Name: .reloc_max
+ Type: STT_SECTION
+ Section: .reloc_max
+ - Name: L3
+ Section: .reloc_max
+ - Name: L4
+ Section: .reloc_max
+ Value: 0x0000000000000004
+ - Name: .reloc_min
+ Type: STT_SECTION
+ Section: .reloc_min
+ - Name: L5
+ Section: .reloc_min
+ - Name: L6
+ Section: .reloc_min
+ Value: 0x0000000000000004
+ Global:
+ - Name: _start
+ Section: .reloc_zero
+...
diff --git a/test/ELF/riscv-pcrel-hilo.test b/test/ELF/riscv-pcrel-hilo.test
new file mode 100644
index 000000000000..9767e14903c3
--- /dev/null
+++ b/test/ELF/riscv-pcrel-hilo.test
@@ -0,0 +1,103 @@
+# .option norelax
+# .global _start
+#
+# _start:
+# auipc a0, %pcrel_hi(_start + 4)
+# addi a0, a0, %pcrel_lo(_start)
+#
+# .section .reloc_neg, "ax", @progbits
+# L1:
+# auipc a0, %pcrel_hi(L1 - 2)
+# addi a0, a0, %pcrel_lo(L1)
+#
+#
+# REQUIRES: riscv
+# RUN: yaml2obj %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: obj2yaml %t | FileCheck %s
+#
+# CHECK: - Name: .text
+# CHECK: Content: '1705000013054500'
+# 11000: 00000517 auipc a0,0x0
+# 11004: 00450513 addi a0,a0,4 # 11004 <_start+0x4>
+#
+# CHECK: - Name: .reloc_neg
+# CHECK: Content: 170500001305E5FF
+# 11008: 00000517 auipc a0,0x0
+# 1100c: ffe50513 addi a0,a0,-2 # 11006 <_start+0x6>
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_RISCV
+ Flags: [ EF_RISCV_RVC, EF_RISCV_FLOAT_ABI_SOFT ]
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000002
+ Content: '1705000013050500'
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: _start
+ Type: R_RISCV_PCREL_HI20
+ Addend: 4
+ - Offset: 0x0000000000000004
+ Symbol: _start
+ Type: R_RISCV_PCREL_LO12_I
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ Content: ''
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000001
+ - Name: .reloc_neg
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000001
+ Content: '1705000013050500'
+ - Name: .rela.reloc_neg
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: .reloc_neg
+ Relocations:
+ - Offset: 0x0000000000000000
+ Symbol: L1
+ Type: R_RISCV_PCREL_HI20
+ Addend: -2
+ - Offset: 0x0000000000000004
+ Symbol: L1
+ Type: R_RISCV_PCREL_LO12_I
+Symbols:
+ Local:
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ - Name: .reloc_neg
+ Type: STT_SECTION
+ Section: .reloc_neg
+ - Name: L1
+ Section: .reloc_neg
+ Global:
+ - Name: _start
+ Section: .text
+...
diff --git a/test/ELF/shared.s b/test/ELF/shared.s
index 3a8fedec9240..e00dd9937ff2 100644
--- a/test/ELF/shared.s
+++ b/test/ELF/shared.s
@@ -141,7 +141,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: _DYNAMIC
-// CHECK-NEXT: Value: 0x12000
+// CHECK-NEXT: Value: 0x402000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
@@ -152,7 +152,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: _start
-// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Value: 0x401000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: None
@@ -181,7 +181,7 @@
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
@@ -190,8 +190,8 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: _start@
-// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Name: _start
+// CHECK-NEXT: Value: 0x401000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: Non
@@ -199,7 +199,7 @@
// CHECK-NEXT: Section: .text
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: bar@
+// CHECK-NEXT: Name: bar
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
@@ -208,7 +208,7 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: zed@
+// CHECK-NEXT: Name: zed
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
@@ -220,7 +220,7 @@
// DONT_EXPORT: DynamicSymbols [
// DONT_EXPORT-NEXT: Symbol {
-// DONT_EXPORT-NEXT: Name: @
+// DONT_EXPORT-NEXT: Name:
// DONT_EXPORT-NEXT: Value: 0x0
// DONT_EXPORT-NEXT: Size: 0
// DONT_EXPORT-NEXT: Binding: Local (0x0)
@@ -229,7 +229,7 @@
// DONT_EXPORT-NEXT: Section: Undefined (0x0)
// DONT_EXPORT-NEXT: }
// DONT_EXPORT-NEXT: Symbol {
-// DONT_EXPORT-NEXT: Name: bar@
+// DONT_EXPORT-NEXT: Name: bar
// DONT_EXPORT-NEXT: Value: 0x0
// DONT_EXPORT-NEXT: Size: 0
// DONT_EXPORT-NEXT: Binding: Global
@@ -238,7 +238,7 @@
// DONT_EXPORT-NEXT: Section: Undefined
// DONT_EXPORT-NEXT: }
// DONT_EXPORT-NEXT: Symbol {
-// DONT_EXPORT-NEXT: Name: zed@
+// DONT_EXPORT-NEXT: Name: zed
// DONT_EXPORT-NEXT: Value: 0x0
// DONT_EXPORT-NEXT: Size: 0
// DONT_EXPORT-NEXT: Binding: Global
diff --git a/test/ELF/sort-norosegment.s b/test/ELF/sort-norosegment.s
index cd4fc9ebae16..108713f8d1c8 100644
--- a/test/ELF/sort-norosegment.s
+++ b/test/ELF/sort-norosegment.s
@@ -2,7 +2,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t %t.o -shared
-# RUN: llvm-readelf -s %t | FileCheck %s
+# RUN: llvm-readelf -S %t | FileCheck %s
# CHECK: .dynsym {{.*}} A
# CHECK-NEXT: .hash {{.*}} A
diff --git a/test/ELF/static-error.s b/test/ELF/static-error.s
new file mode 100644
index 000000000000..1ae98ab2c324
--- /dev/null
+++ b/test/ELF/static-error.s
@@ -0,0 +1,13 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared.s -o %t.o
+// RUN: ld.lld -shared -o %t.so %t.o
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld -o /dev/null %t.o %t.so
+// RUN: not ld.lld -o /dev/null -static %t.o %t.so 2>&1 | FileCheck %s
+
+// CHECK: attempted static link of dynamic object
+
+.global _start
+_start:
+ nop
diff --git a/test/ELF/static-with-export-dynamic.s b/test/ELF/static-with-export-dynamic.s
index f0c67df22623..a718babc2cf6 100644
--- a/test/ELF/static-with-export-dynamic.s
+++ b/test/ELF/static-with-export-dynamic.s
@@ -18,7 +18,7 @@
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: _start
-// CHECK-NEXT: Value: 0x11000
+// CHECK-NEXT: Value: 0x401000
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Global
// CHECK-NEXT: Type: None
diff --git a/test/ELF/strip-debug.s b/test/ELF/strip-debug.s
index 8005cfacee6c..e5295f10d1ec 100644
--- a/test/ELF/strip-debug.s
+++ b/test/ELF/strip-debug.s
@@ -1,4 +1,4 @@
-# REQUIRES: x86
+# REQUIRES: x86, zlib
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: ld.lld %t -o %t2 --strip-debug
# RUN: llvm-readobj -sections %t2 | FileCheck %s
@@ -12,3 +12,5 @@
.section .debug_Foo,"",@progbits
.section .zdebug_Bar,"",@progbits
+.ascii "ZLIB"
+.quad 0
diff --git a/test/ELF/symbol-ordering-file-warnings.s b/test/ELF/symbol-ordering-file-warnings.s
index 71414bf58098..abbafc4e3754 100644
--- a/test/ELF/symbol-ordering-file-warnings.s
+++ b/test/ELF/symbol-ordering-file-warnings.s
@@ -19,11 +19,6 @@
# 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 \
@@ -97,7 +92,7 @@
# 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
+# RUN: 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
@@ -115,10 +110,12 @@
# ABSOLUTE: warning: {{.*}}1.o: unable to order absolute symbol: absolute
# WARN-NOT: warning:
# MISSING: warning: symbol ordering file: no such symbol: missing
+# WARN-NOT: warning:
# MISSING2: warning: symbol ordering file: no such symbol: missing_sym
+# WARN-NOT: warning:
# 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:
+# MULTI: warning: {{.*}}2.o: unable to order absolute symbol: multi
# WARN-NOT: warning:
absolute = 0x1234
diff --git a/test/ELF/textrel.s b/test/ELF/textrel.s
new file mode 100644
index 000000000000..fac67d542af7
--- /dev/null
+++ b/test/ELF/textrel.s
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux-gnu %s -o %t.o
+
+# Without --warn-text-ifunc, lld should run fine:
+# RUN: ld.lld -z notext %t.o -o %t2
+
+# With --warn-text-ifunc, lld should run with warnings:
+# RUN: ld.lld --warn-ifunc-textrel -z notext %t.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: using ifunc symbols when text relocations are allowed may produce
+# CHECK-SAME: a binary that will segfault, if the object file is linked with
+# CHECK-SAME: old version of glibc (glibc 2.28 and earlier). If this applies to
+# CHECK-SAME: you, consider recompiling the object files without -fPIC and
+# CHECK-SAME: without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to
+# CHECK-SAME: turn off this warning.
+# CHECK: >>> defined in {{.*}}
+# CHECK: >>> referenced by {{.*}}:(.text+0x8)
+
+# Without text relocations, lld should run fine:
+# RUN: ld.lld --fatal-warnings %t.o -o /dev/null
+
+.text
+.globl a_func_impl
+a_func_impl:
+ nop
+
+.globl selector
+.type selector,@function
+selector:
+ movl $a_func_impl, %eax
+ retq
+
+.globl a_func
+.type a_func,@gnu_indirect_function
+.set a_func, selector
+
+.globl _start
+.type _start,@function
+main:
+ callq a_func
+ retq
diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s
index c411fc74cd68..31c9494c6f24 100644
--- a/test/ELF/tls-i686.s
+++ b/test/ELF/tls-i686.s
@@ -32,16 +32,16 @@ _start:
// DIS: Disassembly of section test:
// DIS-NEXT: _start:
-// DIS-NEXT: 11000: ba 08 00 00 00 movl $8, %edx
-// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
-// DIS-NEXT: 1100c: 29 d0 subl %edx, %eax
-// DIS-NEXT: 1100e: ba 04 00 00 00 movl $4, %edx
-// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
-// DIS-NEXT: 1101a: 29 d0 subl %edx, %eax
-// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
-// DIS-NEXT: 11023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax
-// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
-// DIS-NEXT: 11030: 8d 81 77 00 00 00 leal 119(%ecx), %eax
+// DIS-NEXT: 401000: ba 08 00 00 00 movl $8, %edx
+// DIS-NEXT: 401005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 40100c: 29 d0 subl %edx, %eax
+// DIS-NEXT: 40100e: ba 04 00 00 00 movl $4, %edx
+// DIS-NEXT: 401013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 40101a: 29 d0 subl %edx, %eax
+// DIS-NEXT: 40101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 401023: 8d 81 f8 ff ff ff leal -8(%ecx), %eax
+// DIS-NEXT: 401029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx
+// DIS-NEXT: 401030: 8d 81 77 00 00 00 leal 119(%ecx), %eax
// RELOC: Relocations [
// RELOC-NEXT: ]
diff --git a/test/ELF/tls-in-archive.s b/test/ELF/tls-in-archive.s
index ac1b4cc11ea4..5a8791dd2b3c 100644
--- a/test/ELF/tls-in-archive.s
+++ b/test/ELF/tls-in-archive.s
@@ -1,5 +1,6 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-in-archive.s -o %t1.o
+// RUN: rm -f %t.a
// 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 /dev/null
diff --git a/test/ELF/tls-opt-gdiele-i686.s b/test/ELF/tls-opt-gdiele-i686.s
index b39f933e2fdb..1baaf111cbfa 100644
--- a/test/ELF/tls-opt-gdiele-i686.s
+++ b/test/ELF/tls-opt-gdiele-i686.s
@@ -8,21 +8,21 @@
// NORELOC: Relocations [
// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
-// NORELOC-NEXT: 0x12058 R_386_TLS_TPOFF tlsshared0 0x0
-// NORELOC-NEXT: 0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// NORELOC-NEXT: 0x402058 R_386_TLS_TPOFF tlsshared0 0x0
+// NORELOC-NEXT: 0x40205C R_386_TLS_TPOFF tlsshared1 0x0
// NORELOC-NEXT: }
// NORELOC-NEXT: ]
// DISASM: Disassembly of section .text:
// DISASM-NEXT: _start:
-// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11006: 03 83 f8 ff ff ff addl -8(%ebx), %eax
-// DISASM-NEXT: 1100c: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11012: 03 83 fc ff ff ff addl -4(%ebx), %eax
-// DISASM-NEXT: 11018: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 1101e: 81 e8 08 00 00 00 subl $8, %eax
-// DISASM-NEXT: 11024: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 1102a: 81 e8 04 00 00 00 subl $4, %eax
+// DISASM-NEXT: 401000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401006: 03 83 f8 ff ff ff addl -8(%ebx), %eax
+// DISASM-NEXT: 40100c: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401012: 03 83 fc ff ff ff addl -4(%ebx), %eax
+// DISASM-NEXT: 401018: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 40101e: 81 e8 08 00 00 00 subl $8, %eax
+// DISASM-NEXT: 401024: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 40102a: 81 e8 04 00 00 00 subl $4, %eax
.type tlsexe1,@object
.section .tbss,"awT",@nobits
diff --git a/test/ELF/tls-opt-i686.s b/test/ELF/tls-opt-i686.s
index d8b1d0eca0b7..0f9d4d6ff522 100644
--- a/test/ELF/tls-opt-i686.s
+++ b/test/ELF/tls-opt-i686.s
@@ -10,25 +10,25 @@
// DISASM: Disassembly of section .text:
// DISASM-NEXT: _start:
// LD -> LE:
-// DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11006: 90 nop
-// DISASM-NEXT: 11007: 8d 74 26 00 leal (%esi,%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,%eiz), %esi
-// DISASM-NEXT: 1101c: 8d 90 fc ff ff ff leal -4(%eax), %edx
+// DISASM-NEXT: 401000: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401006: 90 nop
+// DISASM-NEXT: 401007: 8d 74 26 00 leal (%esi,%eiz), %esi
+// DISASM-NEXT: 40100b: 8d 90 f8 ff ff ff leal -8(%eax), %edx
+// DISASM-NEXT: 401011: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401017: 90 nop
+// DISASM-NEXT: 401018: 8d 74 26 00 leal (%esi,%eiz), %esi
+// DISASM-NEXT: 40101c: 8d 90 fc ff ff ff leal -4(%eax), %edx
// IE -> LE:
// 4294967288 == 0xFFFFFFF8
// 4294967292 == 0xFFFFFFFC
-// DISASM-NEXT: 11022: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11028: c7 c0 f8 ff ff ff movl $4294967288, %eax
-// DISASM-NEXT: 1102e: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11034: c7 c0 fc ff ff ff movl $4294967292, %eax
-// DISASM-NEXT: 1103a: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 11040: 8d 80 f8 ff ff ff leal -8(%eax), %eax
-// DISASM-NEXT: 11046: 65 a1 00 00 00 00 movl %gs:0, %eax
-// DISASM-NEXT: 1104c: 8d 80 fc ff ff ff leal -4(%eax), %eax
+// DISASM-NEXT: 401022: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401028: c7 c0 f8 ff ff ff movl $4294967288, %eax
+// DISASM-NEXT: 40102e: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401034: c7 c0 fc ff ff ff movl $4294967292, %eax
+// DISASM-NEXT: 40103a: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 401040: 8d 80 f8 ff ff ff leal -8(%eax), %eax
+// DISASM-NEXT: 401046: 65 a1 00 00 00 00 movl %gs:0, %eax
+// DISASM-NEXT: 40104c: 8d 80 fc ff ff ff leal -4(%eax), %eax
.type tls0,@object
.section .tbss,"awT",@nobits
.globl tls0
diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s
index 50655e34a4ff..704928b2b4dd 100644
--- a/test/ELF/tls-opt-iele-i686-nopic.s
+++ b/test/ELF/tls-opt-iele-i686-nopic.s
@@ -14,7 +14,7 @@
// GOTREL-NEXT: SHF_ALLOC
// GOTREL-NEXT: SHF_WRITE
// GOTREL-NEXT: ]
-// GOTREL-NEXT: Address: 0x12058
+// GOTREL-NEXT: Address: 0x402058
// GOTREL-NEXT: Offset: 0x2058
// GOTREL-NEXT: Size: 8
// GOTREL-NEXT: Link: 0
@@ -24,8 +24,8 @@
// GOTREL-NEXT: }
// GOTREL: Relocations [
// GOTREL-NEXT: Section ({{.*}}) .rel.dyn {
-// GOTREL-NEXT: 0x12058 R_386_TLS_TPOFF tlsshared0 0x0
-// GOTREL-NEXT: 0x1205C R_386_TLS_TPOFF tlsshared1 0x0
+// GOTREL-NEXT: 0x402058 R_386_TLS_TPOFF tlsshared0 0x0
+// GOTREL-NEXT: 0x40205C R_386_TLS_TPOFF tlsshared1 0x0
// GOTREL-NEXT: }
// GOTREL-NEXT: ]
@@ -33,24 +33,24 @@
// DISASM-NEXT: _start:
// 4294967288 = 0xFFFFFFF8
// 4294967292 = 0xFFFFFFFC
-// 73808 = (.got)[0] = 0x12058
-// 73812 = (.got)[1] = 0x1205C
-// DISASM-NEXT: 11000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
-// DISASM-NEXT: 11006: 65 8b 01 movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11009: b8 f8 ff ff ff movl $4294967288, %eax
-// DISASM-NEXT: 1100e: 65 8b 00 movl %gs:(%eax), %eax
-// DISASM-NEXT: 11011: 81 c1 f8 ff ff ff addl $4294967288, %ecx
-// DISASM-NEXT: 11017: 65 8b 01 movl %gs:(%ecx), %eax
-// DISASM-NEXT: 1101a: c7 c1 fc ff ff ff movl $4294967292, %ecx
-// DISASM-NEXT: 11020: 65 8b 01 movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11023: b8 fc ff ff ff movl $4294967292, %eax
-// DISASM-NEXT: 11028: 65 8b 00 movl %gs:(%eax), %eax
-// DISASM-NEXT: 1102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
-// DISASM-NEXT: 11031: 65 8b 01 movl %gs:(%ecx), %eax
-// DISASM-NEXT: 11034: 8b 0d 58 20 01 00 movl 73816, %ecx
-// DISASM-NEXT: 1103a: 65 8b 01 movl %gs:(%ecx), %eax
-// DISASM-NEXT: 1103d: 03 0d 5c 20 01 00 addl 73820, %ecx
-// DISASM-NEXT: 11043: 65 8b 01 movl %gs:(%ecx), %eax
+// 4202584 = (.got)[0] = 0x402058
+// 4202588 = (.got)[1] = 0x40205C
+// DISASM-NEXT: 401000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
+// DISASM-NEXT: 401006: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 401009: b8 f8 ff ff ff movl $4294967288, %eax
+// DISASM-NEXT: 40100e: 65 8b 00 movl %gs:(%eax), %eax
+// DISASM-NEXT: 401011: 81 c1 f8 ff ff ff addl $4294967288, %ecx
+// DISASM-NEXT: 401017: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 40101a: c7 c1 fc ff ff ff movl $4294967292, %ecx
+// DISASM-NEXT: 401020: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 401023: b8 fc ff ff ff movl $4294967292, %eax
+// DISASM-NEXT: 401028: 65 8b 00 movl %gs:(%eax), %eax
+// DISASM-NEXT: 40102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
+// DISASM-NEXT: 401031: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 401034: 8b 0d 58 20 40 00 movl 4202584, %ecx
+// DISASM-NEXT: 40103a: 65 8b 01 movl %gs:(%ecx), %eax
+// DISASM-NEXT: 40103d: 03 0d 5c 20 40 00 addl 4202588, %ecx
+// DISASM-NEXT: 401043: 65 8b 01 movl %gs:(%ecx), %eax
.type tlslocal0,@object
.section .tbss,"awT",@nobits
diff --git a/test/ELF/tls-static.s b/test/ELF/tls-static.s
index 3e1aead01a30..61d504b2e850 100644
--- a/test/ELF/tls-static.s
+++ b/test/ELF/tls-static.s
@@ -4,7 +4,6 @@
// 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
.global _start
_start:
diff --git a/test/ELF/tls-weak-undef.s b/test/ELF/tls-weak-undef.s
index 7aa6ef13a2af..1023aebbc258 100644
--- a/test/ELF/tls-weak-undef.s
+++ b/test/ELF/tls-weak-undef.s
@@ -4,6 +4,7 @@
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \
// RUN: %p/Inputs/tls-in-archive.s -o %t1.o
+// RUN: rm -f %t.a
// RUN: llvm-ar cru %t.a %t1.o
// RUN: ld.lld %t.o %t.a -o %t
diff --git a/test/ELF/trace-ar.s b/test/ELF/trace-ar.s
index 1d178dc9dd37..0a71f7eba9f4 100644
--- a/test/ELF/trace-ar.s
+++ b/test/ELF/trace-ar.s
@@ -2,6 +2,7 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.foo.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar1.s -o %t.obj1.o
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/trace-ar2.s -o %t.obj2.o
+# RUN: rm -f %t.boo.a
# RUN: llvm-ar rcs %t.boo.a %t.obj1.o %t.obj2.o
## Check how -t works with achieves
diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s
index b5c1ddc2a558..63004b7c18aa 100644
--- a/test/ELF/trace-symbols.s
+++ b/test/ELF/trace-symbols.s
@@ -8,7 +8,9 @@
# RUN: %p/Inputs/trace-symbols-foo-strong.s -o %t2
# RUN: ld.lld -shared %t1 -o %t1.so
# RUN: ld.lld -shared %t2 -o %t2.so
+# RUN: rm -f %t1.a
# RUN: llvm-ar rcs %t1.a %t1
+# RUN: rm -f %t2.a
# RUN: llvm-ar rcs %t2.a %t2
# RUN: ld.lld -y foo -trace-symbol common -trace-symbol=hsymbol \
diff --git a/test/ELF/undef-broken-debug.test b/test/ELF/undef-broken-debug.test
index b93d399f36c2..c3405ad0b9ed 100644
--- a/test/ELF/undef-broken-debug.test
+++ b/test/ELF/undef-broken-debug.test
@@ -5,7 +5,7 @@
# The debug info has a broken relocation. Check that we don't crash
# and still report the undefined symbol.
-# CHECK: error: unsupported relocation target while parsing debug info
+# CHECK: error: {{.*}}.o: relocation R_X86_64_64 at 0x29 has unsupported target
# CHECK: error: undefined symbol: bar
--- !ELF
diff --git a/test/ELF/undef-version-script.s b/test/ELF/undef-version-script.s
index 712589e2444f..7ef4b7a22ca7 100644
--- a/test/ELF/undef-version-script.s
+++ b/test/ELF/undef-version-script.s
@@ -6,7 +6,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -15,7 +15,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: bar@
+# CHECK-NEXT: Name: bar
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Weak (0x2)
@@ -24,7 +24,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo@
+# CHECK-NEXT: Name: foo
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Global (0x1)
diff --git a/test/ELF/undef-with-plt-addr-i686.s b/test/ELF/undef-with-plt-addr-i686.s
index 755f0daced2e..cd1b3fdfe2a2 100644
--- a/test/ELF/undef-with-plt-addr-i686.s
+++ b/test/ELF/undef-with-plt-addr-i686.s
@@ -17,7 +17,7 @@ mov $set_data, %eax
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_EXECINSTR
// CHECK-NEXT: ]
-// CHECK-NEXT: Address: 0x11010
+// CHECK-NEXT: Address: 0x401010
// CHECK: Name: set_data
-// CHECK-NEXT: Value: 0x11020
+// CHECK-NEXT: Value: 0x401020
diff --git a/test/ELF/undef.s b/test/ELF/undef.s
index 07e3b689a236..e6277e36667d 100644
--- a/test/ELF/undef.s
+++ b/test/ELF/undef.s
@@ -3,6 +3,7 @@
# 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: rm -f %t2.a
# RUN: llvm-ar rc %t2.a %t2.o
# 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
@@ -19,6 +20,9 @@
# CHECK: >>> referenced by undef.s
# CHECK: >>> {{.*}}:(.text+0x10)
+# CHECK: error: undefined symbol: vtable for Foo
+# CHECK: the vtable symbol may be undefined because the class is missing its key function (see https://lld.llvm.org/missingkeyfunction)
+
# CHECK: error: undefined symbol: zed2
# CHECK: >>> referenced by {{.*}}.o:(.text+0x0) in archive {{.*}}2.a
@@ -59,3 +63,4 @@ _start:
call bar
call zed1
call _Z3fooi
+ call _ZTV3Foo
diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s
index c8444c4e0663..db50e7c8f49f 100644
--- a/test/ELF/verdef-defaultver.s
+++ b/test/ELF/verdef-defaultver.s
@@ -8,7 +8,7 @@
# DSO: DynamicSymbols [
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: Value: 0x0
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Local
@@ -61,7 +61,7 @@
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 0
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: }
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 2
@@ -112,7 +112,7 @@
# EXE: DynamicSymbols [
# EXE-NEXT: Symbol {
-# EXE-NEXT: Name: @
+# EXE-NEXT: Name:
# EXE-NEXT: Value: 0x0
# EXE-NEXT: Size: 0
# EXE-NEXT: Binding: Local
@@ -156,7 +156,7 @@
# EXE-NEXT: Symbols [
# EXE-NEXT: Symbol {
# EXE-NEXT: Version: 0
-# EXE-NEXT: Name: @
+# EXE-NEXT: Name:
# EXE-NEXT: }
# EXE-NEXT: Symbol {
# EXE-NEXT: Version: 2
diff --git a/test/ELF/verdef.s b/test/ELF/verdef.s
index b5d12ee3884f..9fc5bdd4f279 100644
--- a/test/ELF/verdef.s
+++ b/test/ELF/verdef.s
@@ -14,7 +14,7 @@
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 0
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: }
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 2
@@ -76,7 +76,7 @@
# MAIN-NEXT: Symbols [
# MAIN-NEXT: Symbol {
# MAIN-NEXT: Version: 0
-# MAIN-NEXT: Name: @
+# MAIN-NEXT: Name:
# MAIN-NEXT: }
# MAIN-NEXT: Symbol {
# MAIN-NEXT: Version: 2
diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s
index 6e87f046e304..e8b65c40663a 100644
--- a/test/ELF/verneed.s
+++ b/test/ELF/verneed.s
@@ -76,7 +76,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -125,7 +125,7 @@
# CHECK-NEXT: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 2
diff --git a/test/ELF/version-exclude-libs.s b/test/ELF/version-exclude-libs.s
index 7335c2315eba..a25a08f14b6f 100644
--- a/test/ELF/version-exclude-libs.s
+++ b/test/ELF/version-exclude-libs.s
@@ -1,5 +1,6 @@
// REQUIRES: x86
// RUN: llvm-mc %p/Inputs/versiondef.s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: rm -f %t.a
// 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
diff --git a/test/ELF/version-script-complex-wildcards.s b/test/ELF/version-script-complex-wildcards.s
index ce001d0b76c3..1ba34787646d 100644
--- a/test/ELF/version-script-complex-wildcards.s
+++ b/test/ELF/version-script-complex-wildcards.s
@@ -4,14 +4,14 @@
# RUN: echo "FOO { global: extern \"C++\" { ab[c]*; }; };" > %t.script
# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so
# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=ABC
-# ABC: Name: _Z3abbi@
+# ABC: Name: _Z3abbi
# ABC: Name: _Z3abci@@FOO
# RUN: echo "FOO { global: extern \"C++\" { ab[b]*; }; };" > %t1.script
# RUN: ld.lld --version-script %t1.script -shared %t.o -o %t1.so
# RUN: llvm-readobj -V %t1.so | FileCheck %s --check-prefix=ABB
# ABB: Name: _Z3abbi@@FOO
-# ABB: Name: _Z3abci@
+# ABB: Name: _Z3abci
# RUN: echo "FOO { global: extern \"C++\" { ab[a-b]*; }; };" > %t2.script
# RUN: ld.lld --version-script %t2.script -shared %t.o -o %t2.so
@@ -34,8 +34,8 @@
# RUN: echo "FOO { global: extern \"C++\" { ab[^a-c]*; }; };" > %t6.script
# RUN: ld.lld --version-script %t6.script -shared %t.o -o %t6.so
# RUN: llvm-readobj -V %t6.so | FileCheck %s --check-prefix=NO
-# NO: Name: _Z3abbi@
-# NO: Name: _Z3abci@
+# NO: Name: _Z3abbi
+# NO: Name: _Z3abci
# RUN: echo "FOO { global: extern \"C++\" { ab[^c-z]*; }; };" > %t7.script
# RUN: ld.lld --version-script %t7.script -shared %t.o -o %t7.so
diff --git a/test/ELF/version-script-extern-undefined.s b/test/ELF/version-script-extern-undefined.s
index 518b122ce7cd..8bff4050b621 100644
--- a/test/ELF/version-script-extern-undefined.s
+++ b/test/ELF/version-script-extern-undefined.s
@@ -8,11 +8,11 @@
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 1
-# CHECK-NEXT: Name: _Z3abbi@
+# CHECK-NEXT: Name: _Z3abbi
# CHECK-NEXT: }
# CHECK-NEXT: ]
diff --git a/test/ELF/version-script-extern-wildcards.s b/test/ELF/version-script-extern-wildcards.s
index 472fc1f7833e..27660b25cb02 100644
--- a/test/ELF/version-script-extern-wildcards.s
+++ b/test/ELF/version-script-extern-wildcards.s
@@ -8,7 +8,7 @@
# CHECK: Version symbols {
# CHECK: Symbols [
-# CHECK: Name: _Z3bari@
+# CHECK: Name: _Z3bari
# CHECK: Name: _Z3fooi@@FOO
# CHECK: Name: _Z3zedi@@BAR
diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s
index 16f400354356..682afb09fa34 100644
--- a/test/ELF/version-script-extern.s
+++ b/test/ELF/version-script-extern.s
@@ -12,7 +12,7 @@
# DSO: DynamicSymbols [
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: Value: 0x0
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Local
@@ -74,7 +74,7 @@
# DSO-NEXT: Symbols [
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 0
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: }
# DSO-NEXT: Symbol {
# DSO-NEXT: Version: 3
diff --git a/test/ELF/version-script-extern2.s b/test/ELF/version-script-extern2.s
index 834bbe1122e5..245cb0076533 100644
--- a/test/ELF/version-script-extern2.s
+++ b/test/ELF/version-script-extern2.s
@@ -8,7 +8,7 @@
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 2
diff --git a/test/ELF/version-script-hide-so-symbol.s b/test/ELF/version-script-hide-so-symbol.s
index b4f58be06de7..c84e37a5ac45 100644
--- a/test/ELF/version-script-hide-so-symbol.s
+++ b/test/ELF/version-script-hide-so-symbol.s
@@ -12,7 +12,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
diff --git a/test/ELF/version-script-locals-extern.s b/test/ELF/version-script-locals-extern.s
index 12e8771b8eff..ca1d7173eb91 100644
--- a/test/ELF/version-script-locals-extern.s
+++ b/test/ELF/version-script-locals-extern.s
@@ -7,11 +7,11 @@
# ABB: Symbols [
# ABB-NEXT: Symbol {
# ABB-NEXT: Version: 0
-# ABB-NEXT: Name: @
+# ABB-NEXT: Name:
# ABB-NEXT: }
# ABB-NEXT: Symbol {
# ABB-NEXT: Version: 1
-# ABB-NEXT: Name: _Z3abci@
+# ABB-NEXT: Name: _Z3abci
# ABB-NEXT: }
# ABB-NEXT: ]
@@ -26,11 +26,11 @@
# ABC: Symbols [
# ABC-NEXT: Symbol {
# ABC-NEXT: Version: 0
-# ABC-NEXT: Name: @
+# ABC-NEXT: Name:
# ABC-NEXT: }
# ABC-NEXT: Symbol {
# ABC-NEXT: Version: 1
-# ABC-NEXT: Name: _Z3abbi@
+# ABC-NEXT: Name: _Z3abbi
# ABC-NEXT: }
# ABC-NEXT: ]
diff --git a/test/ELF/version-script-symver2.s b/test/ELF/version-script-symver2.s
index 5961d9a7c3a6..8441e1930abc 100644
--- a/test/ELF/version-script-symver2.s
+++ b/test/ELF/version-script-symver2.s
@@ -7,7 +7,7 @@
# CHECK: Symbols [
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 0
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
# CHECK-NEXT: Version: 3
diff --git a/test/ELF/version-script-weak.s b/test/ELF/version-script-weak.s
index cc3df8da5dc5..887d6f94d890 100644
--- a/test/ELF/version-script-weak.s
+++ b/test/ELF/version-script-weak.s
@@ -14,7 +14,7 @@
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK: Symbol {
-# CHECK: Name: foo@
+# CHECK: Name: foo
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Weak
diff --git a/test/ELF/version-script.s b/test/ELF/version-script.s
index 75083ac9a767..5f2f3c44c9b2 100644
--- a/test/ELF/version-script.s
+++ b/test/ELF/version-script.s
@@ -50,7 +50,7 @@
# DSO: DynamicSymbols [
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: @
+# DSO-NEXT: Name:
# DSO-NEXT: Value: 0x0
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Local (0x0)
@@ -59,7 +59,7 @@
# DSO-NEXT: Section: Undefined (0x0)
# DSO-NEXT: }
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: bar@
+# DSO-NEXT: Name: bar
# DSO-NEXT: Value: 0x0
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Global (0x1)
@@ -68,7 +68,7 @@
# DSO-NEXT: Section: Undefined (0x0)
# DSO-NEXT: }
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: foo1@
+# DSO-NEXT: Name: foo1
# DSO-NEXT: Value: 0x1000
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Global (0x1)
@@ -77,7 +77,7 @@
# DSO-NEXT: Section: .text
# DSO-NEXT: }
# DSO-NEXT: Symbol {
-# DSO-NEXT: Name: foo3@
+# DSO-NEXT: Name: foo3
# DSO-NEXT: Value: 0x1007
# DSO-NEXT: Size: 0
# DSO-NEXT: Binding: Global (0x1)
@@ -89,7 +89,7 @@
# DSO2: DynamicSymbols [
# DSO2-NEXT: Symbol {
-# DSO2-NEXT: Name: @
+# DSO2-NEXT: Name:
# DSO2-NEXT: Value: 0x0
# DSO2-NEXT: Size: 0
# DSO2-NEXT: Binding: Local (0x0)
@@ -98,7 +98,7 @@
# DSO2-NEXT: Section: Undefined (0x0)
# DSO2-NEXT: }
# DSO2-NEXT: Symbol {
-# DSO2-NEXT: Name: bar@
+# DSO2-NEXT: Name: bar
# DSO2-NEXT: Value: 0x0
# DSO2-NEXT: Size: 0
# DSO2-NEXT: Binding: Global (0x1)
@@ -110,7 +110,7 @@
# VERDSO: DynamicSymbols [
# VERDSO-NEXT: Symbol {
-# VERDSO-NEXT: Name: @
+# VERDSO-NEXT: Name:
# VERDSO-NEXT: Value: 0x0
# VERDSO-NEXT: Size: 0
# VERDSO-NEXT: Binding: Local
@@ -119,7 +119,7 @@
# VERDSO-NEXT: Section: Undefined
# VERDSO-NEXT: }
# VERDSO-NEXT: Symbol {
-# VERDSO-NEXT: Name: bar@
+# VERDSO-NEXT: Name: bar
# VERDSO-NEXT: Value: 0x0
# VERDSO-NEXT: Size: 0
# VERDSO-NEXT: Binding: Global
@@ -158,7 +158,7 @@
# ALL: DynamicSymbols [
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: @
+# ALL-NEXT: Name:
# ALL-NEXT: Value: 0x0
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Local
@@ -167,7 +167,7 @@
# ALL-NEXT: Section: Undefined
# ALL-NEXT: }
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: _start@
+# ALL-NEXT: Name: _start
# ALL-NEXT: Value:
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Global
@@ -176,7 +176,7 @@
# ALL-NEXT: Section: .text
# ALL-NEXT: }
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: bar@
+# ALL-NEXT: Name: bar
# ALL-NEXT: Value:
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Global
@@ -185,7 +185,7 @@
# ALL-NEXT: Section: Undefined
# ALL-NEXT: }
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: foo1@
+# ALL-NEXT: Name: foo1
# ALL-NEXT: Value:
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Global
@@ -194,7 +194,7 @@
# ALL-NEXT: Section: .text
# ALL-NEXT: }
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: foo2@
+# ALL-NEXT: Name: foo2
# ALL-NEXT: Value:
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Global
@@ -203,7 +203,7 @@
# ALL-NEXT: Section: .text
# ALL-NEXT: }
# ALL-NEXT: Symbol {
-# ALL-NEXT: Name: foo3@
+# ALL-NEXT: Name: foo3
# ALL-NEXT: Value:
# ALL-NEXT: Size: 0
# ALL-NEXT: Binding: Global
diff --git a/test/ELF/version-wildcard.test b/test/ELF/version-wildcard.test
index ac0b7edc6c51..f9a43319a837 100644
--- a/test/ELF/version-wildcard.test
+++ b/test/ELF/version-wildcard.test
@@ -7,7 +7,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local
@@ -52,7 +52,7 @@
# MIX: DynamicSymbols [
# MIX-NEXT: Symbol {
-# MIX-NEXT: Name: @
+# MIX-NEXT: Name:
# MIX-NEXT: Value: 0x0
# MIX-NEXT: Size: 0
# MIX-NEXT: Binding: Local
diff --git a/test/ELF/visibility.s b/test/ELF/visibility.s
index 0582d718e8ee..b9e9b55836a8 100644
--- a/test/ELF/visibility.s
+++ b/test/ELF/visibility.s
@@ -82,7 +82,7 @@
// CHECK: DynamicSymbols [
// CHECK-NEXT: Symbol {
-// CHECK-NEXT: Name: @
+// CHECK-NEXT: Name:
// CHECK-NEXT: Value: 0x0
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
diff --git a/test/ELF/weak-undef-export.s b/test/ELF/weak-undef-export.s
index 164bc1730832..561a0571a413 100644
--- a/test/ELF/weak-undef-export.s
+++ b/test/ELF/weak-undef-export.s
@@ -8,7 +8,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @ (0)
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -17,7 +17,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo@ (1)
+# CHECK-NEXT: Name: foo
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Weak (0x2)
diff --git a/test/ELF/weak-undef.s b/test/ELF/weak-undef.s
index 09c2a4c4440f..e7905c33876c 100644
--- a/test/ELF/weak-undef.s
+++ b/test/ELF/weak-undef.s
@@ -5,7 +5,7 @@
# CHECK: DynamicSymbols [
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: @
+# CHECK-NEXT: Name:
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Local (0x0)
@@ -14,7 +14,7 @@
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: foo@
+# CHECK-NEXT: Name: foo
# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
# CHECK-NEXT: Binding: Weak
diff --git a/test/ELF/wrap-entry.s b/test/ELF/wrap-entry.s
new file mode 100644
index 000000000000..c746b8e6d118
--- /dev/null
+++ b/test/ELF/wrap-entry.s
@@ -0,0 +1,13 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+
+// RUN: ld.lld -o %t.exe %t.o -wrap=_start
+// RUN: llvm-readobj -file-headers %t.exe | FileCheck %s
+
+// CHECK: Entry: 0x201001
+
+.global _start, __wrap__start
+_start:
+ nop
+__wrap__start:
+ nop
diff --git a/test/ELF/wrap-no-real.s b/test/ELF/wrap-no-real.s
index 100efa6bbc28..2dba291ac9d4 100644
--- a/test/ELF/wrap-no-real.s
+++ b/test/ELF/wrap-no-real.s
@@ -15,60 +15,14 @@
// CHECK-NEXT: movl $0x11010, %edx
// CHECK-NEXT: movl $0x11000, %edx
-// RUN: llvm-readobj -t %t | FileCheck -check-prefix=SYM %s
+// RUN: llvm-objdump -t %t | FileCheck -check-prefix=SYM %s
-// Test the full symbol table. It is verbose, but lld at times
-// produced duplicated symbols which are hard to test otherwise.
-// SYM: Symbols [
-// SYM-NEXT: Symbol {
-// SYM-NEXT: Name: (0)
-// SYM-NEXT: Value:
-// SYM-NEXT: Size:
-// SYM-NEXT: Binding:
-// SYM-NEXT: Type
-// SYM-NEXT: Other:
-// SYM-NEXT: Section:
-// SYM-NEXT: }
-// SYM-NEXT: Symbol {
-// SYM-NEXT: Name: _DYNAMIC
-// SYM-NEXT: Value:
-// SYM-NEXT: Size:
-// SYM-NEXT: Binding:
-// SYM-NEXT: Type:
-// SYM-NEXT: Other [
-// SYM-NEXT: STV_HIDDEN
-// SYM-NEXT: ]
-// SYM-NEXT: Section: .dynamic
-// SYM-NEXT: }
-// SYM-NEXT: Symbol {
-// SYM-NEXT: Name: foo
-// SYM-NEXT: Value: 0x11000
-// SYM-NEXT: Size:
-// SYM-NEXT: Binding:
-// SYM-NEXT: Type:
-// SYM-NEXT: Other:
-// SYM-NEXT: Section:
-// SYM-NEXT: }
-// SYM-NEXT: Symbol {
-// SYM-NEXT: Name: _start
-// SYM-NEXT: Value:
-// SYM-NEXT: Size:
-// SYM-NEXT: Binding:
-// SYM-NEXT: Type
-// SYM-NEXT: Other:
-// SYM-NEXT: Section:
-// SYM-NEXT: }
-// SYM-NEXT: Symbol {
-// SYM-NEXT: Name: __wrap_foo
-// SYM-NEXT: Value: 0x11010
-// SYM-NEXT: Size:
-// SYM-NEXT: Binding:
-// SYM-NEXT: Type:
-// SYM-NEXT: Other:
-// SYM-NEXT: Section:
-// SYM-NEXT: }
-// SYM-NEXT: ]
+// SYM: 0000000000202000 .dynamic 00000000 .hidden _DYNAMIC
+// SYM-NEXT: 0000000000011000 *ABS* 00000000 __real_foo
+// SYM-NEXT: 0000000000011010 *ABS* 00000000 __wrap_foo
+// SYM-NEXT: 0000000000201000 .text 00000000 _start
+// SYM-NEXT: 0000000000011000 *ABS* 00000000 foo
.global _start
_start:
diff --git a/test/ELF/wrap-plt.s b/test/ELF/wrap-plt.s
new file mode 100644
index 000000000000..71f533dc5a9c
--- /dev/null
+++ b/test/ELF/wrap-plt.s
@@ -0,0 +1,45 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+
+// RUN: ld.lld -o %t2 %t -wrap foo -shared
+// RUN: llvm-readobj -s -r %t2 | FileCheck %s
+// RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s
+
+// CHECK: Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1020
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 48
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT __wrap_foo 0x0
+// CHECK-NEXT: 0x2020 R_X86_64_JUMP_SLOT _start 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
+
+// DISASM: _start:
+// DISASM-NEXT: jmp 41
+// DISASM-NEXT: jmp 36
+// DISASM-NEXT: jmp 47
+
+.global foo
+foo:
+ nop
+
+.global __wrap_foo
+__wrap_foo:
+ nop
+
+.global _start
+_start:
+ jmp foo@plt
+ jmp __wrap_foo@plt
+ jmp _start@plt
diff --git a/test/ELF/wrap-with-archive.s b/test/ELF/wrap-with-archive.s
new file mode 100644
index 000000000000..1bfbdcef30dd
--- /dev/null
+++ b/test/ELF/wrap-with-archive.s
@@ -0,0 +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 %p/Inputs/wrap-with-archive.s -o %t2
+// RUN: llvm-ar rcs %t3 %t2
+// RUN: ld.lld -o %t4 %t %t3 -wrap get_executable_start
+
+// Regression test for https://bugs.llvm.org/show_bug.cgi?id=40134
+
+.global get_executable_start
+.global _start
+
+_start:
+ jmp get_executable_start
diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s
index a02592e24ebd..1a9726851f7e 100644
--- a/test/ELF/wrap.s
+++ b/test/ELF/wrap.s
@@ -34,7 +34,7 @@
// SYM2-NEXT: STV_PROTECTED
// SYM2-NEXT: ]
// SYM3: Name: __real_foo
-// SYM3-NEXT: Value: 0x11020
+// SYM3-NEXT: Value: 0x11000
// SYM3-NEXT: Size:
// SYM3-NEXT: Binding: Global
// SYM3-NEXT: Type: None
diff --git a/test/ELF/x86-64-combined-dynrel.s b/test/ELF/x86-64-combined-dynrel.s
new file mode 100644
index 000000000000..b1bc697d148b
--- /dev/null
+++ b/test/ELF/x86-64-combined-dynrel.s
@@ -0,0 +1,40 @@
+# REQUIRES: x86
+# RUN: llvm-mc --triple=x86_64-pc-linux -filetype=obj -o %t.o %s
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: .rela.dyn : { *(.rela.dyn) *(.rela.plt) } \
+# RUN: } " > %t.script
+# RUN: ld.lld %t.o -o %t.so --shared --script %t.script
+# RUN: llvm-readobj --section-headers --dynamic-table %t.so | FileCheck %s
+
+// The linker script above combines the .rela.dyn and .rela.plt into a single
+// table. ELF is clear that the DT_PLTRELSZ should match the subset of
+// relocations that is associated with the PLT. It is less clear about what
+// the value of DT_RELASZ should be. ELF implies that it should be the size
+// of the single table so that DT_RELASZ includes DT_PLTRELSZ. The loader in
+// glibc permits this as long as .rela.plt comes after .rela.dyn in the
+// combined table.
+
+ .text
+ .globl func
+ .type func, %function
+ .globl foo
+ .type foo, %object
+
+ .globl _start
+ .type _start, %function
+_start:
+ call func@plt
+ movq func@GOTPCREL (%rip), %rax
+
+# CHECK: Name: .rela.dyn
+# CHECK-NEXT: Type: SHT_RELA
+# CHECK-NEXT: Flags [
+# CHECK-NEXT: SHF_ALLOC
+# CHECK-NEXT: ]
+# CHECK-NEXT: Address:
+# CHECK-NEXT: Offset:
+# CHECK-NEXT: Size: 48
+
+# CHECK: 0x0000000000000008 RELASZ 48
+# CHECK: 0x0000000000000002 PLTRELSZ 24
diff --git a/test/ELF/x86-64-reloc-error2.s b/test/ELF/x86-64-reloc-error2.s
index d49b67522654..230241b2be5f 100644
--- a/test/ELF/x86-64-reloc-error2.s
+++ b/test/ELF/x86-64-reloc-error2.s
@@ -1,14 +1,18 @@
# 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
+# RUN: not ld.lld --entry=func --gc-sections %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]
+# CHECK: {{.*}}.o:(function func: .text.func+0x3): relocation R_X86_64_32S out of range: -281474974609408 is not in [-2147483648, 2147483647]
+
+# This mergeable section will be garbage collected. We had a crash issue in that case. Test it.
+.section .rodata.str1,"aMS",@progbits,1
+.asciz "a"
.section .text.func, "ax", %progbits
.globl func
.type func,@function
-.size func, 0x10
func:
- movq func - 0x1000000000000, %rdx
+ movq $func - 0x1000000000000, %rdx
+.size func, .-func
diff --git a/test/ELF/x86-64-reloc-gotoff64.s b/test/ELF/x86-64-reloc-gotoff64.s
index 697ac17917a2..b78d96e00a6e 100644
--- a/test/ELF/x86-64-reloc-gotoff64.s
+++ b/test/ELF/x86-64-reloc-gotoff64.s
@@ -1,7 +1,7 @@
// 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-readelf -S %t.so | FileCheck %s -check-prefix=SECTION
// RUN: llvm-objdump -d %t.so | FileCheck %s
// SECTION: .dynamic DYNAMIC 0000000000003000
diff --git a/test/ELF/x86-64-reloc-gotpc64.s b/test/ELF/x86-64-reloc-gotpc64.s
index f07376f41218..9c58217b4586 100644
--- a/test/ELF/x86-64-reloc-gotpc64.s
+++ b/test/ELF/x86-64-reloc-gotpc64.s
@@ -1,7 +1,7 @@
// 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-readelf -S %t.so | FileCheck %s -check-prefix=SECTION
// RUN: llvm-objdump -d %t.so | FileCheck %s
// SECTION: .got PROGBITS 0000000000003070 003070 000000
diff --git a/test/ELF/x86-64-reloc-range-debug-loc.s b/test/ELF/x86-64-reloc-range-debug-loc.s
index 8be4df3c5202..08a49607e806 100644
--- a/test/ELF/x86-64-reloc-range-debug-loc.s
+++ b/test/ELF/x86-64-reloc-range-debug-loc.s
@@ -5,7 +5,7 @@
## 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]
+# CHECK: error: test.s:3:(.text+0x1): relocation R_X86_64_32 out of range: 68719476736 is not in [0, 4294967295]
.section .text,"ax",@progbits
foo:
diff --git a/test/ELF/x86-64-reloc-range.s b/test/ELF/x86-64-reloc-range.s
index c58a692821ec..87e3379da859 100644
--- a/test/ELF/x86-64-reloc-range.s
+++ b/test/ELF/x86-64-reloc-range.s
@@ -1,6 +1,8 @@
// REQUIRES: x86
// RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj
// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s
+// RUN: ld.lld --noinhibit-exec -shared %t.o -o %t 2>&1 | FileCheck %s
+// RUN: ls %t
// 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-retpoline-znow-static-iplt.s b/test/ELF/x86-64-retpoline-znow-static-iplt.s
new file mode 100644
index 000000000000..70355c05e2cd
--- /dev/null
+++ b/test/ELF/x86-64-retpoline-znow-static-iplt.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+# RUN: ld.lld -z retpolineplt -z now %t.o -o %t
+# RUN: llvm-objdump -d -no-show-raw-insn %t | FileCheck %s
+
+#0x201001+5 + 42 = 0x201030 (foo@plt)
+# CHECK: _start:
+# CHECK-NEXT: 201001: callq 42
+
+#Static IPLT header due to -z retpolineplt
+# CHECK: 0000000000201010 .plt:
+# CHECK-NEXT: 201010: callq 11 <.plt+0x10>
+# CHECK-NEXT: 201015: pause
+# CHECK-NEXT: 201017: lfence
+#foo@plt
+# CHECK: 201030: movq 4041(%rip), %r11
+# CHECK-NEXT: 201037: jmp -44 <.plt>
+
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.globl _start
+_start:
+ call foo
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-fail.s b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
index 0ae3de5ea611..b2d21e1595a3 100644
--- a/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s
@@ -1,14 +1,18 @@
# 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: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-extra.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t3.o
-# RUN: not ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s
+# RUN: not ld.lld --defsym __morestack=0x100 --defsym __more_stack_nonsplit=0x200 %t1.o %t2.o %t3.o -o %t 2>&1 | FileCheck %s
# An unknown prologue gives a match failure
-# CHECK: unable to adjust the enclosing function's
+# CHECK: error: {{.*}}.o:(.text): unknown_prologue (with -fsplit-stack) calls non_split (without -fsplit-stack), but couldn't adjust its prologue
# 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
+# RELOCATABLE: cannot mix split-stack and non-split-stack in a relocatable link
+
+# RUN: not ld.lld --defsym __morestack=0x100 --defsym _start=0x300 %t1.o %t2.o %t3.o -o %t 2>&1 | FileCheck %s -check-prefix=ERROR
+# ERROR: Mixing split-stack objects requires a definition of __morestack_non_split
.text
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-shared.s b/test/ELF/x86-64-split-stack-prologue-adjust-shared.s
new file mode 100644
index 000000000000..9da2dde2e208
--- /dev/null
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-shared.s
@@ -0,0 +1,31 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-extra.s -o %t2.o
+# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t2.o -o %t4.so -shared
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t4.so -o %t
+# RUN: llvm-objdump -d %t | FileCheck %s
+
+# For a cross .so call, make sure lld produced the conservative call to __morestack_non_split.
+# CHECK: prologue1_cross_so_call:
+# CHECK-NEXT: stc{{.*$}}
+# CHECK-NEXT: nopl{{.*$}}
+# CHECK: jae{{.*$}}
+# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
+
+ .text
+
+ .global prologue1_cross_so_call
+ .type prologue1_cross_so_call,@function
+prologue1_cross_so_call:
+ cmp %fs:0x70,%rsp
+ jae 1f
+ callq __morestack
+ retq
+1:
+ callq split
+ retq
+ .size prologue1_cross_so_call,. - prologue1_cross_so_call
+
+ .section .note.GNU-stack,"",@progbits
+ .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
index 353eabef0de7..0c82943f8dd1 100644
--- a/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-silent.s
@@ -2,7 +2,7 @@
# 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: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %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
diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-success.s b/test/ELF/x86-64-split-stack-prologue-adjust-success.s
index bad26677f3fd..fb3493f2c3e7 100644
--- a/test/ELF/x86-64-split-stack-prologue-adjust-success.s
+++ b/test/ELF/x86-64-split-stack-prologue-adjust-success.s
@@ -1,8 +1,9 @@
# 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: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-extra.s -o %t2.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t3.o
-# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t -z notext
+# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o %t3.o -o %t -z notext
# RUN: llvm-objdump -d %t | FileCheck %s
# Avoid duplicating the prologue for every test via macros.
@@ -25,11 +26,11 @@ prologue1_calls_\function_to_call:
.size prologue1_calls_\function_to_call,. - prologue1_calls_\function_to_call
.endm
-.macro prologue2 function_to_call register
+.macro prologue2 function_to_call register compare_amount
.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
+ lea -\compare_amount(%rsp),%\register
cmp %fs:0x70,%\register
jae 1f
callq __morestack
@@ -65,20 +66,20 @@ prologue1 split
# 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-NEXT: lea{{.*}} -512(%rsp),{{.*}}%r10
# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
# CHECK: jae{{.*}}
# CHECK-NEXT: callq{{.*}}<__morestack>
-prologue2 split r10
+prologue2 split r10 0x200
# CHECK: prologue2_calls_splitr11:
-# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r11
+# CHECK-NEXT: lea{{.*}} -256(%rsp),{{.*}}%r11
# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}}
# CHECK: jae{{.*}}
# CHECK-NEXT: callq{{.*}}<__morestack>
-prologue2 split r11
+prologue2 split r11 0x100
# 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
@@ -95,30 +96,20 @@ prologue1 non_split
# 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-NEXT: lea{{.*}} -16640(%rsp),{{.*}}%r10
# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r10
# CHECK: jae{{.*$}}
# CHECK-NEXT: callq{{.*}}<__morestack_non_split>
-prologue2 non_split r10
+prologue2 non_split r10 0x100
# CHECK: prologue2_calls_non_splitr11:
-# CHECK-NEXT: lea{{.*$}}
+# CHECK-NEXT: lea{{.*}} -16896(%rsp),{{.*}}%r11
# 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
+prologue2 non_split r11 0x200
.section .note.GNU-stack,"",@progbits
.section .note.GNU-split-stack,"",@progbits
diff --git a/test/ELF/znotext-plt-relocations-protected.s b/test/ELF/znotext-plt-relocations-protected.s
index 4fd8065a2873..37724e74db22 100644
--- a/test/ELF/znotext-plt-relocations-protected.s
+++ b/test/ELF/znotext-plt-relocations-protected.s
@@ -4,7 +4,12 @@
# RUN: ld.lld %t2.o -o %t2.so -shared
# RUN: not ld.lld -z notext %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s
-# CHECK: error: cannot preempt symbol: foo
+# CHECK: error: cannot preempt symbol: foo
+# CHECK-NEXT: >>> defined in {{.*}}2.so
+# CHECK-NEXT: >>> referenced by test.cpp
+# CHECK-NEXT: >>> {{.*}}.o:(.text+0x0)
+
+.file "test.cpp"
.global _start
_start:
diff --git a/test/ELF/zstack-size.s b/test/ELF/zstack-size.s
index 23eed0a79ecc..bec2b2057fb7 100644
--- a/test/ELF/zstack-size.s
+++ b/test/ELF/zstack-size.s
@@ -6,6 +6,9 @@
# RUN: ld.lld -z stack-size=0 %t -o %t2
# RUN: llvm-readobj -program-headers %t2 | FileCheck %s -check-prefix=CHECK2
+# RUN: ld.lld -z stack-size=0x2000 -z stack-size=0x1000 %t -o %t3
+# RUN: llvm-readobj -program-headers %t3 | FileCheck %s -check-prefix=CHECK1
+
.global _start
_start:
nop
diff --git a/test/MinGW/driver.test b/test/MinGW/driver.test
index 35d3ccf97ccd..3222bb1115b8 100644
--- a/test/MinGW/driver.test
+++ b/test/MinGW/driver.test
@@ -145,3 +145,9 @@ 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
+
+RUN: ld.lld -### foo.o -m i386pe -require-defined _foo --require-defined _bar -require-defined=_baz --require-defined=_foo2 | FileCheck -check-prefix=REQUIRE-DEFINED %s
+REQUIRE-DEFINED: -include:_foo -include:_bar -include:_baz -include:_foo2
+
+RUN: ld.lld -### -m i386pep foo.o -Llibpath | FileCheck -check-prefix LIBPATH %s
+LIBPATH: -libpath:libpath
diff --git a/test/lit.cfg.py b/test/lit.cfg.py
index 26880383d354..e53ff8740035 100644
--- a/test/lit.cfg.py
+++ b/test/lit.cfg.py
@@ -45,13 +45,18 @@ tool_patterns = [
llvm_config.add_tool_substitutions(tool_patterns)
+# LLD tests tend to be flaky on NetBSD, so add some retries.
+# We don't do this on other platforms because it's slower.
+if platform.system() in ['NetBSD']:
+ config.test_retry_attempts = 2
+
# When running under valgrind, we mangle '-vg' onto the end of the triple so we
# can check it with XFAIL and XTARGET.
if lit_config.useValgrind:
config.target_triple += '-vg'
# Running on ELF based *nix
-if platform.system() in ['FreeBSD', 'Linux']:
+if platform.system() in ['FreeBSD', 'NetBSD', 'Linux']:
config.available_features.add('system-linker-elf')
# Set if host-cxxabi's demangler can handle target's symbols.
@@ -67,7 +72,9 @@ llvm_config.feature_config(
'AVR': 'avr',
'Hexagon': 'hexagon',
'Mips': 'mips',
+ 'MSP430': 'msp430',
'PowerPC': 'ppc',
+ 'RISCV': 'riscv',
'Sparc': 'sparc',
'WebAssembly': 'wasm',
'X86': 'x86'})
@@ -93,7 +100,10 @@ if config.have_dia_sdk:
tar_executable = lit.util.which('tar', config.environment['PATH'])
if tar_executable:
tar_version = subprocess.Popen(
- [tar_executable, '--version'], stdout=subprocess.PIPE, env={'LANG': 'C'})
- if 'GNU tar' in tar_version.stdout.read().decode():
+ [tar_executable, '--version'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ env={'LANG': 'C'})
+ sout, _ = tar_version.communicate()
+ if 'GNU tar' in sout.decode():
config.available_features.add('gnutar')
- tar_version.wait()
diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in
index 764ab83fbcf2..7475ac7eaa7f 100644
--- a/test/lit.site.cfg.py.in
+++ b/test/lit.site.cfg.py.in
@@ -25,7 +25,8 @@ except KeyError as e:
key, = e.args
lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
-@LIT_SITE_CFG_IN_FOOTER@
+import lit.llvm
+lit.llvm.initialize(lit_config, config)
# Let the main config do the real work.
lit_config.load_config(config, "@LLD_SOURCE_DIR@/test/lit.cfg.py")
diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml
index 2bc7e7c5c2f6..2936ca9fdbfe 100644
--- a/test/mach-o/cstring-sections.yaml
+++ b/test/mach-o/cstring-sections.yaml
@@ -36,25 +36,25 @@ sections:
# CHECK: content: [ 61, 62, 63, 00 ]
# CHECK: merge: by-content
# CHECK: section-choice: custom-required
-# CHECK: section-name: __TEXT/__objc_methname
+# CHECK: section-name: '__TEXT/__objc_methname'
# CHECK: - scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 64, 65, 66, 00 ]
# CHECK: merge: by-content
# CHECK: section-choice: custom-required
-# CHECK: section-name: __TEXT/__objc_methname
+# CHECK: section-name: '__TEXT/__objc_methname'
# CHECK: - scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 61, 62, 63, 00 ]
# CHECK: merge: by-content
# CHECK: section-choice: custom-required
-# CHECK: section-name: __TEXT/__objc_classname
+# CHECK: section-name: '__TEXT/__objc_classname'
# CHECK: - scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 67, 68, 69, 00 ]
# CHECK: merge: by-content
# CHECK: section-choice: custom-required
-# CHECK: section-name: __TEXT/__objc_classname
+# CHECK: section-name: '__TEXT/__objc_classname'
# CHECK: - scope: hidden
# CHECK: type: c-string
# CHECK: content: [ 61, 62, 63, 00 ]
diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml
index 34d688541b91..06b269ae1680 100644
--- a/test/mach-o/dependency_info.yaml
+++ b/test/mach-o/dependency_info.yaml
@@ -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/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml
index d696aff0feff..994289b5cdc6 100644
--- a/test/mach-o/parse-data-relocs-x86_64.yaml
+++ b/test/mach-o/parse-data-relocs-x86_64.yaml
@@ -367,6 +367,6 @@ page-size: 0x00000000
# CHECK: type: unknown
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
# CHECK: section-choice: custom-required
-# CHECK: section-name: __DATA/__custom
+# CHECK: section-name: '__DATA/__custom'
# CHECK: dead-strip: never
diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml
index b1929ef230b6..3b9eb9fb6288 100644
--- a/test/mach-o/parse-data.yaml
+++ b/test/mach-o/parse-data.yaml
@@ -115,5 +115,5 @@ global-symbols:
# CHECK: type: unknown
# CHECK: content: [ 01, 02, 03, 04, 05, 06, 07, 08 ]
# CHECK: section-choice: custom-required
-# CHECK: section-name: __CUST/__custom
+# CHECK: section-name: '__CUST/__custom'
diff --git a/test/mach-o/sectcreate.yaml b/test/mach-o/sectcreate.yaml
index aa32a05a6fb7..bc17dec25a45 100644
--- a/test/mach-o/sectcreate.yaml
+++ b/test/mach-o/sectcreate.yaml
@@ -8,5 +8,5 @@
# CHECK: type: sectcreate
# CHECK: content: [ 68, 65, 6C, 6C, 6F, 0A ]
# CHECK: section-choice: custom-required
-# CHECK: section-name: __DATA/__data
+# CHECK: section-name: '__DATA/__data'
# CHECK: dead-strip: never
diff --git a/test/wasm/Inputs/event-section1.ll b/test/wasm/Inputs/event-section1.ll
new file mode 100644
index 000000000000..89d9e87162f5
--- /dev/null
+++ b/test/wasm/Inputs/event-section1.ll
@@ -0,0 +1,9 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @llvm.wasm.throw(i32, i8*)
+
+define void @foo(i8* %p) {
+ call void @llvm.wasm.throw(i32 0, i8* %p)
+ ret void
+}
diff --git a/test/wasm/Inputs/event-section2.ll b/test/wasm/Inputs/event-section2.ll
new file mode 100644
index 000000000000..3499db9298af
--- /dev/null
+++ b/test/wasm/Inputs/event-section2.ll
@@ -0,0 +1,9 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @llvm.wasm.throw(i32, i8*)
+
+define void @bar(i8* %p) {
+ call void @llvm.wasm.throw(i32 0, i8* %p)
+ ret void
+}
diff --git a/test/wasm/Inputs/globals.yaml b/test/wasm/Inputs/globals.yaml
index c08a3044ec95..a2c4602294ef 100644
--- a/test/wasm/Inputs/globals.yaml
+++ b/test/wasm/Inputs/globals.yaml
@@ -34,7 +34,7 @@ Sections:
Offset: 0x00000004
- Type: CUSTOM
Name: linking
- Version: 1
+ Version: 2
SymbolTable:
- Index: 0
Kind: GLOBAL
diff --git a/test/wasm/Inputs/undefined-globals.yaml b/test/wasm/Inputs/undefined-globals.yaml
index 440a538d6587..49cf8811f812 100644
--- a/test/wasm/Inputs/undefined-globals.yaml
+++ b/test/wasm/Inputs/undefined-globals.yaml
@@ -32,7 +32,7 @@ Sections:
Offset: 0x00000004
- Type: CUSTOM
Name: linking
- Version: 1
+ Version: 2
SymbolTable:
- Index: 0
Kind: GLOBAL
diff --git a/test/wasm/alias.ll b/test/wasm/alias.ll
index f88452e538c4..358582ea1520 100644
--- a/test/wasm/alias.ll
+++ b/test/wasm/alias.ll
@@ -1,5 +1,5 @@
; RUN: llc -filetype=obj -o %t.o %s
-; RUN: wasm-ld %t.o -o %t.wasm
+; RUN: wasm-ld --export=start_alias %t.o -o %t.wasm
; RUN: obj2yaml %t.wasm | FileCheck %s
target triple = "wasm32-unknown-unknown"
@@ -25,7 +25,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0, 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000001
diff --git a/test/wasm/archive-export.ll b/test/wasm/archive-export.ll
new file mode 100644
index 000000000000..37256ce37244
--- /dev/null
+++ b/test/wasm/archive-export.ll
@@ -0,0 +1,50 @@
+Test that --export will also fetch lazy symbols from archives
+
+RUN: llc -filetype=obj %S/Inputs/start.ll -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: rm -f %t.a
+RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o
+RUN: wasm-ld --export-dynamic --export=archive2_symbol -o %t.wasm %t.a %t.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+RUN: wasm-ld --export-dynamic -o %t.wasm %t.a %t.o
+RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=NOEXPORT
+
+CHECK: 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: foo
+CHECK-NEXT: Kind: FUNCTION
+CHECK-NEXT: Index: 2
+CHECK-NEXT: - Name: bar
+CHECK-NEXT: Kind: FUNCTION
+CHECK-NEXT: Index: 3
+CHECK-NEXT: - Name: archive2_symbol
+CHECK-NEXT: Kind: FUNCTION
+CHECK-NEXT: Index: 4
+CHECK-NEXT: - Name: _start
+CHECK-NEXT: Kind: FUNCTION
+CHECK-NEXT: Index: 1
+CHECK-NEXT: - Type: CODE
+
+NOEXPORT: Exports:
+NOEXPORT-NEXT: - Name: memory
+NOEXPORT-NEXT: Kind: MEMORY
+NOEXPORT-NEXT: Index: 0
+NOEXPORT-NEXT: - Name: __heap_base
+NOEXPORT-NEXT: Kind: GLOBAL
+NOEXPORT-NEXT: Index: 1
+NOEXPORT-NEXT: - Name: __data_end
+NOEXPORT-NEXT: Kind: GLOBAL
+NOEXPORT-NEXT: Index: 2
+NOEXPORT-NEXT: - Name: _start
+NOEXPORT-NEXT: Kind: FUNCTION
+NOEXPORT-NEXT: Index: 1
+NOEXPORT-NEXT: - Type: CODE
diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll
index 50f72d627386..beea2725cff9 100644
--- a/test/wasm/archive.ll
+++ b/test/wasm/archive.ll
@@ -3,6 +3,7 @@
; 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: rm -f %t.a
; 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
diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll
index 63a6def87382..7f8fe474f414 100644
--- a/test/wasm/call-indirect.ll
+++ b/test/wasm/call-indirect.ll
@@ -1,6 +1,6 @@
; 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: wasm-ld --export-dynamic -o %t.wasm %t2.o %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; bitcode generated from the following C code:
@@ -60,7 +60,7 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: FunctionTypes: [ 3, 0, 3, 1, 3, 4 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000003
@@ -105,9 +105,6 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Name: __data_end
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 2
-; CHECK-NEXT: - Name: _start
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: bar
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
@@ -117,6 +114,9 @@ define void @call_ptr(i64 (i64)* %arg) {
; CHECK-NEXT: - Name: foo
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Name: indirect_func
; CHECK-NEXT: Kind: GLOBAL
; CHECK-NEXT: Index: 3
diff --git a/test/wasm/comdats.ll b/test/wasm/comdats.ll
index d0bec4cda146..9baea22050ef 100644
--- a/test/wasm/comdats.ll
+++ b/test/wasm/comdats.ll
@@ -1,7 +1,7 @@
; 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: wasm-ld --export-dynamic -o %t.wasm %t.o %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
target triple = "wasm32-unknown-unknown"
diff --git a/test/wasm/compress-relocs.ll b/test/wasm/compress-relocs.ll
index b137d5abd43e..d14ea26a4c33 100644
--- a/test/wasm/compress-relocs.ll
+++ b/test/wasm/compress-relocs.ll
@@ -1,9 +1,11 @@
; 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: wasm-ld --export-dynamic -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: wasm-ld --export-dynamic -O2 -o %t-opt.wasm %t2.o %t.o
+; RUN: obj2yaml %t-opt.wasm | FileCheck %s
+; RUN: not wasm-ld --compress-relocations -o %t-compressed.wasm %t2.o %t.o 2>&1 | FileCheck %s -check-prefix=ERROR
+; RUN: wasm-ld --export-dynamic --strip-debug --compress-relocations -o %t-compressed.wasm %t2.o %t.o
; RUN: obj2yaml %t-compressed.wasm | FileCheck %s -check-prefix=COMPRESS
target triple = "wasm32-unknown-unknown-wasm"
@@ -18,5 +20,7 @@ entry:
ret void
}
+; ERROR: wasm-ld: error: --compress-relocations is incompatible with output debug information. Please pass --strip-debug or --strip-all
+
; CHECK: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B
; COMPRESS: Body: 41002802840821004100280280081100001A20001101001A0B
diff --git a/test/wasm/cxx-mangling.ll b/test/wasm/cxx-mangling.ll
index 67f3594e8166..e1f4ea4950a6 100644
--- a/test/wasm/cxx-mangling.ll
+++ b/test/wasm/cxx-mangling.ll
@@ -1,8 +1,8 @@
; 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
+; RUN: wasm-ld --export=_Z3fooi --demangle -o %t_demangle.wasm %t.o
+; RUN: obj2yaml %t_demangle.wasm | FileCheck --check-prefixes=CHECK,DEMANGLE %s
+; RUN: wasm-ld --export=_Z3fooi --no-demangle -o %t_nodemangle.wasm %t.o
+; RUN: obj2yaml %t_nodemangle.wasm | FileCheck --check-prefixes=CHECK,MANGLE %s
target triple = "wasm32-unknown-unknown"
@@ -32,12 +32,12 @@ define void @_start() {
; 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: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 0
@@ -58,9 +58,11 @@ define void @_start() {
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: __wasm_call_ctors
; CHECK-NEXT: - Index: 1
-; CHECK-NEXT: Name: 'undefined function bar(int)'
+; DEMANGLE-NEXT: Name: 'undefined function bar(int)'
+; MANGLE-NEXT: Name: undefined function _Z3bari
; CHECK-NEXT: - Index: 2
-; CHECK-NEXT: Name: 'foo(int)'
+; DEMANGLE-NEXT: Name: 'foo(int)'
+; MANGLE-NEXT: Name: _Z3fooi
; 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 5fd3f2d7791c..b01c13ac9b82 100644
--- a/test/wasm/data-layout.ll
+++ b/test/wasm/data-layout.ll
@@ -68,6 +68,16 @@ target triple = "wasm32-unknown-unknown"
; CHECK-MAX-NEXT: Initial: 0x00000002
; CHECK-MAX-NEXT: Maximum: 0x00000002
+; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry --shared-memory \
+; 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-SHARED
+
+; CHECK-SHARED: - Type: MEMORY
+; CHECK-SHARED-NEXT: Memories:
+; CHECK-SHARED-NEXT: - Flags: [ HAS_MAX, IS_SHARED ]
+; CHECK-SHARED-NEXT: Initial: 0x00000002
+; CHECK-SHARED-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
diff --git a/test/wasm/data-segment-merging.ll b/test/wasm/data-segment-merging.ll
index d0df84d0fc23..2a48b2db6e37 100644
--- a/test/wasm/data-segment-merging.ll
+++ b/test/wasm/data-segment-merging.ll
@@ -5,44 +5,27 @@ target triple = "wasm32-unknown-unknown"
@c = hidden global [9 x i8] c"whatever\00", align 1
@d = hidden global i32 42, align 4
+@e = private constant [9 x i8] c"constant\00", align 1
+@f = private constant i8 43, 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
+; MERGE: - Type: DATA
+; MERGE: Segments:
+; MERGE: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000
+; MERGE: Content: 636F6E7374616E74000000002B
+; MERGE-NOT: Content:
; 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
+; SEPARATE: - Type: DATA
+; SEPARATE: Segments:
+; SEPARATE: Content: 68656C6C6F00
+; SEPARATE: Content: 676F6F6462796500
+; SEPARATE: Content: '776861746576657200'
+; SEPARATE: Content: 2A000000
+; SEPARATE: Content: 636F6E7374616E7400
+; SEPARATE: Content: 2B
+; SEPARATE-NOT: Content:
diff --git a/test/wasm/debug-removed-fn.ll b/test/wasm/debug-removed-fn.ll
new file mode 100644
index 000000000000..8f5f6507f3da
--- /dev/null
+++ b/test/wasm/debug-removed-fn.ll
@@ -0,0 +1,44 @@
+; RUN: llc -filetype=obj < %s -o %t.o
+; RUN: wasm-ld %t.o --no-entry --export=foo -o %t.wasm
+; RUN: llvm-dwarfdump -debug-line %t.wasm | FileCheck %s
+
+; CHECK: Address
+; CHECK: 0x0000000000000005
+; CHECK: 0x0000000000000000
+
+; ModuleID = 't.bc'
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: noinline nounwind optnone
+define hidden i32 @foo() #0 !dbg !7 {
+entry:
+ ret i32 42, !dbg !11
+}
+
+; Function Attrs: noinline nounwind optnone
+define hidden i32 @bar() #0 !dbg !12 {
+entry:
+ ret i32 6, !dbg !13
+}
+
+attributes #0 = { noinline nounwind optnone "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" }
+
+!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 337293)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
+!1 = !DIFile(filename: "t.c", directory: "/d/y")
+!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 337293)"}
+!7 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocation(line: 2, column: 3, scope: !7)
+!12 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 5, type: !8, isLocal: false, isDefinition: true, scopeLine: 5, isOptimized: false, unit: !0, retainedNodes: !2)
+!13 = !DILocation(line: 6, column: 3, scope: !12)
diff --git a/test/wasm/debuginfo.test b/test/wasm/debuginfo.test
index ce68a03bcbce..3e07ad960842 100644
--- a/test/wasm/debuginfo.test
+++ b/test/wasm/debuginfo.test
@@ -43,7 +43,7 @@ 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_type (0x00000097 "int[2]")
CHECK-NEXT: DW_AT_external (true)
CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
CHECK-NEXT: DW_AT_decl_line (1)
@@ -65,7 +65,7 @@ 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_type (0x00000097 "int[2]")
CHECK-NEXT: DW_AT_external (true)
CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c")
CHECK-NEXT: DW_AT_decl_line (8)
diff --git a/test/wasm/demangle.ll b/test/wasm/demangle.ll
index f0416bb6b32f..64fa46ae4dce 100644
--- a/test/wasm/demangle.ll
+++ b/test/wasm/demangle.ll
@@ -1,17 +1,19 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: not wasm-ld --undefined _Z3fooi \
-; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s
+; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s
-; CHECK: error: undefined symbol: foo(int)
+; CHECK: error: {{.*}}.o: 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
+; RUN: not wasm-ld --no-demangle \
+; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s
-; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi
+; CHECK-NODEMANGLE: error: {{.*}}.o: undefined symbol: _Z3fooi
target triple = "wasm32-unknown-unknown"
+declare void @_Z3fooi(i32);
+
define hidden void @_start() local_unnamed_addr {
entry:
+ call void @_Z3fooi(i32 1)
ret void
}
diff --git a/test/wasm/event-section.ll b/test/wasm/event-section.ll
new file mode 100644
index 000000000000..1610287b4a3b
--- /dev/null
+++ b/test/wasm/event-section.ll
@@ -0,0 +1,34 @@
+; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %p/Inputs/event-section1.ll -o %t1.o
+; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %p/Inputs/event-section2.ll -o %t2.o
+; RUN: llc -filetype=obj -exception-model=wasm -mattr=+exception-handling %s -o %t.o
+; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o
+; 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 @foo(i8*)
+declare void @bar(i8*)
+
+define void @_start() {
+ call void @foo(i8* null)
+ call void @bar(i8* null)
+ ret void
+}
+
+; CHECK: 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: - Type: EVENT
+; CHECK-NEXT: Events:
+; CHECK-NEXT: - Index: 0
+; CHECK-NEXT: Attribute: 0
+; CHECK-NEXT: SigIndex: 1
diff --git a/test/wasm/export-all.ll b/test/wasm/export-all.ll
index 34797aac76f7..f903df9160d3 100644
--- a/test/wasm/export-all.ll
+++ b/test/wasm/export-all.ll
@@ -42,7 +42,7 @@ entry:
; CHECK-NOT: - Name: internal_func
; EXPORT: - Type: EXPORT
-; EXPORT: - Name: _start
; EXPORT: - Name: bar
; EXPORT: - Name: foo
+; EXPORT: - Name: _start
; EXPORT-NOT: - Name: internal_func
diff --git a/test/wasm/export-table.test b/test/wasm/export-table.test
index 58775b928f7f..e2d05f00d5a7 100644
--- a/test/wasm/export-table.test
+++ b/test/wasm/export-table.test
@@ -6,7 +6,7 @@
# CHECK: - Type: TABLE
# CHECK-NEXT: Tables:
-# CHECK-NEXT: - ElemType: ANYFUNC
+# CHECK-NEXT: - ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Flags: [ HAS_MAX ]
# CHECK-NEXT: Initial: 0x00000001
diff --git a/test/wasm/export.ll b/test/wasm/export.ll
index 16b2b6ca57cc..519aafebbe23 100644
--- a/test/wasm/export.ll
+++ b/test/wasm/export.ll
@@ -28,10 +28,10 @@ entry:
; 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: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Type: CODE
diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test
index 49bf06b74832..0a64afd6ce20 100644
--- a/test/wasm/import-memory.test
+++ b/test/wasm/import-memory.test
@@ -31,3 +31,20 @@
# CHECK-MAX-NEXT: Initial: 0x00000004
# CHECK-MAX-NEXT: Maximum: 0x00000005
# CHECK-MAX-NEXT: - Type:
+
+# RUN: wasm-ld --import-memory --shared-memory --initial-memory=262144 \
+# RUN: --max-memory=327680 -o %t.max.wasm %t.start.o
+# RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-SHARED %s
+
+# Verify the --shared-memory flag works with imports
+
+# CHECK-SHARED: - Type: IMPORT
+# CHECK-SHARED-NEXT: Imports:
+# CHECK-SHARED-NEXT: - Module: env
+# CHECK-SHARED-NEXT: Field: memory
+# CHECK-SHARED-NEXT: Kind: MEMORY
+# CHECK-SHARED-NEXT: Memory:
+# CHECK-SHARED-NEXT: Flags: [ HAS_MAX, IS_SHARED ]
+# CHECK-SHARED-NEXT: Initial: 0x00000004
+# CHECK-SHARED-NEXT: Maximum: 0x00000005
+# CHECK-SHARED-NEXT: - Type:
diff --git a/test/wasm/import-table.test b/test/wasm/import-table.test
index eb767090292a..440509b3483c 100644
--- a/test/wasm/import-table.test
+++ b/test/wasm/import-table.test
@@ -10,9 +10,7 @@
# CHECK-NEXT: Field: __indirect_function_table
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Table:
-# CHECK-NEXT: ElemType: ANYFUNC
+# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
-# CHECK-NEXT: Flags: [ HAS_MAX ]
# CHECK-NEXT: Initial: 0x00000001
-# CHECK-NEXT: Maximum: 0x00000001
diff --git a/test/wasm/load-undefined.test b/test/wasm/load-undefined.test
index 160cb485ac34..1b8d259d5b8d 100644
--- a/test/wasm/load-undefined.test
+++ b/test/wasm/load-undefined.test
@@ -4,6 +4,7 @@
; 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: rm -f %t2.a
; 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
@@ -17,9 +18,9 @@
; 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: - Index: 3
+; CHECK-NEXT: Name: ret32
; CHECK-NEXT: ...
; NO-LOAD: Name: name
@@ -32,9 +33,6 @@
; 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
+; Verify that referencing a symbol that is not found doesn't result in a link
+; failure. This matches the behaviour of the ELF linker.
+; RUN: wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist
diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll
index 5471466eb076..dd92b4ec9bc5 100644
--- a/test/wasm/local-symbols.ll
+++ b/test/wasm/local-symbols.ll
@@ -1,5 +1,6 @@
+; Test that internal symbols can still be GC'd when with --export-dynamic.
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld -o %t.wasm %t.o
+; RUN: wasm-ld --export-dynamic -o %t.wasm %t.o
; RUN: obj2yaml %t.wasm | FileCheck %s
target triple = "wasm32-unknown-unknown"
@@ -35,7 +36,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000001
diff --git a/test/wasm/locals-duplicate.test b/test/wasm/locals-duplicate.test
index 3c67cdd8cfa4..2d6bd0df5314 100644
--- a/test/wasm/locals-duplicate.test
+++ b/test/wasm/locals-duplicate.test
@@ -1,6 +1,6 @@
; 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: wasm-ld --export-dynamic --no-entry -o %t.wasm %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
; CHECK: --- !WASM
@@ -20,7 +20,7 @@
; CHECK-NEXT: 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000007
@@ -253,7 +253,7 @@
; RELOC-NEXT: 0, 0 ]
; RELOC-NEXT: - Type: TABLE
; RELOC-NEXT: Tables:
-; RELOC-NEXT: - ElemType: ANYFUNC
+; RELOC-NEXT: - ElemType: FUNCREF
; RELOC-NEXT: Limits:
; RELOC-NEXT: Flags: [ HAS_MAX ]
; RELOC-NEXT: Initial: 0x00000007
@@ -382,7 +382,7 @@
; RELOC-NEXT: Content: '0000000000000000'
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
-; RELOC-NEXT: Version: 1
+; RELOC-NEXT: Version: 2
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
@@ -516,15 +516,15 @@
; RELOC-NEXT: SegmentInfo:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Name: .bss.colliding_global1
-; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Index: 1
; RELOC-NEXT: Name: .bss.colliding_global2
-; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Index: 2
; RELOC-NEXT: Name: .bss.colliding_global3
-; RELOC-NEXT: Alignment: 4
+; RELOC-NEXT: Alignment: 2
; RELOC-NEXT: Flags: [ ]
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: name
diff --git a/test/wasm/lto/archive.ll b/test/wasm/lto/archive.ll
index 89fa840cdec5..ab067d8cdce4 100644
--- a/test/wasm/lto/archive.ll
+++ b/test/wasm/lto/archive.ll
@@ -2,7 +2,7 @@
; 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: wasm-ld --export-dynamic %t2.o %t.a -o %t3
; RUN: obj2yaml %t3 | FileCheck %s
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
diff --git a/test/wasm/lto/cache.ll b/test/wasm/lto/cache.ll
index b0a7820c1e19..6d52b973f0fa 100644
--- a/test/wasm/lto/cache.ll
+++ b/test/wasm/lto/cache.ll
@@ -1,5 +1,7 @@
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
+; NetBSD: noatime mounts currently inhibit 'touch' from updating atime
+; UNSUPPORTED: system-netbsd
; RUN: rm -Rf %t.cache && mkdir %t.cache
; Create two files that would be removed by cache pruning due to age.
@@ -11,12 +13,16 @@
; 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: 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
+; Increase the age of llvmcache-foo, which will give it the oldest time stamp
+; so that it is processed and removed first.
+; RUN: %python -c 'import os,sys,time; t=time.time()-120; os.utime(sys.argv[1],(t,t))' %t.cache/llvmcache-foo
+
; 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
diff --git a/test/wasm/lto/export.ll b/test/wasm/lto/export.ll
index 44ded6f147f6..0ff0be504eda 100644
--- a/test/wasm/lto/export.ll
+++ b/test/wasm/lto/export.ll
@@ -29,10 +29,10 @@ entry:
; 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: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Type: CODE
diff --git a/test/wasm/lto/signature-mismatch.ll b/test/wasm/lto/signature-mismatch.ll
new file mode 100644
index 000000000000..e48bb39cd8d9
--- /dev/null
+++ b/test/wasm/lto/signature-mismatch.ll
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj -o %t.o %s
+; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o
+; RUN: not wasm-ld --fatal-warnings %t.o %t1.o -o %t.wasm 2>&1 | FileCheck %s
+
+; Test that functions defined in bitcode correctly report signature
+; mistmaches with existing undefined sybmols in normal objects.
+
+target triple = "wasm32-unknown-unknown"
+
+; f is defined to take no argument in archive.ll which is compiled to bitcode
+declare void @f(i32);
+
+define void @_start() {
+ call void @f(i32 0)
+ ret void
+}
+
+; CHECK: >>> defined as (i32) -> void in {{.*}}signature-mismatch.ll.tmp1.o
+; CHECK: >>> defined as () -> void in lto.tmp
diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll
index 02ad9aab51a0..e2191bed9ed6 100644
--- a/test/wasm/many-functions.ll
+++ b/test/wasm/many-functions.ll
@@ -815,7 +815,7 @@ entry:
; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: Version: 1
+; CHECK-NEXT: Version: 2
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
@@ -1482,9 +1482,9 @@ entry:
; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .data.g0
-; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Alignment: 2
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: .data.foo
-; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Alignment: 2
; CHECK-NEXT: Flags: [ ]
diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll
index 4e8a887f31d8..c503afa81232 100644
--- a/test/wasm/relocatable.ll
+++ b/test/wasm/relocatable.ll
@@ -63,7 +63,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000004
@@ -157,7 +157,7 @@ entry:
; CHECK-NEXT: Content: '616263'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: Version: 1
+; CHECK-NEXT: Version: 2
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
@@ -232,27 +232,27 @@ entry:
; CHECK-NEXT: SegmentInfo:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Name: .rodata.hello_str
-; CHECK-NEXT: Alignment: 1
+; CHECK-NEXT: Alignment: 0
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 1
; CHECK-NEXT: Name: .data.func_addr1
-; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Alignment: 2
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 2
; CHECK-NEXT: Name: .data.func_addr2
-; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Alignment: 2
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Name: .data.func_addr3
-; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Alignment: 2
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Name: .data.data_addr1
-; CHECK-NEXT: Alignment: 8
+; CHECK-NEXT: Alignment: 3
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: - Index: 5
; CHECK-NEXT: Name: .rodata.data_comdat
-; CHECK-NEXT: Alignment: 1
+; CHECK-NEXT: Alignment: 0
; CHECK-NEXT: Flags: [ ]
; CHECK-NEXT: Comdats:
; CHECK-NEXT: - Name: func_comdat
diff --git a/test/wasm/shared.ll b/test/wasm/shared.ll
new file mode 100644
index 000000000000..f3abd1172778
--- /dev/null
+++ b/test/wasm/shared.ll
@@ -0,0 +1,82 @@
+; RUN: llc -O0 -filetype=obj %s -o %t.o
+; RUN: wasm-ld -shared -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+@data = hidden global i32 2, align 4
+@indirect_func = local_unnamed_addr global void ()* @foo, align 4
+@indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4
+
+define default void @foo() {
+entry:
+ ; To ensure we use __stack_pointer
+ %ptr = alloca i32
+ %0 = load i32, i32* @data, align 4
+ %1 = load i32, i32* @data_external, align 4
+ %2 = load void ()*, void ()** @indirect_func, align 4
+ call void %2()
+ ret void
+}
+
+declare void @func_external()
+
+@data_external = external global i32
+
+
+; check for dylink section at start
+
+; CHECK: Sections:
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: dylink
+; CHECK-NEXT: MemorySize: 8
+; CHECK-NEXT: MemoryAlignment: 2
+; CHECK-NEXT: TableSize: 2
+; CHECK-NEXT: TableAlignment: 0
+
+; check for import of __table_base and __memory_base globals
+
+; 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: FUNCREF
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Initial: 0x00000002
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __stack_pointer
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I32
+; CHECK-NEXT: GlobalMutable: true
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __memory_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I32
+; CHECK-NEXT: GlobalMutable: false
+; CHECK-NEXT: - Module: env
+; CHECK-NEXT: Field: __table_base
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: GlobalType: I32
+; CHECK-NEXT: GlobalMutable: false
+
+; check for elem segment initialized with __table_base global as offset
+
+; CHECK: - Type: ELEM
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Opcode: GLOBAL_GET
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: Functions: [ 2, 0 ]
+
+; check the data segment initialized with __memory_base global as offset
+
+; CHECK: - Type: DATA
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - SectionOffset: 6
+; CHECK-NEXT: MemoryIndex: 0
+; CHECK-NEXT: Offset:
+; CHECK-NEXT: Opcode: GLOBAL_GET
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: Content: '0000000001000000'
diff --git a/test/wasm/signature-mismatch-weak.ll b/test/wasm/signature-mismatch-weak.ll
index dbf73d1aa46e..4d2b02cc9ed3 100644
--- a/test/wasm/signature-mismatch-weak.ll
+++ b/test/wasm/signature-mismatch-weak.ll
@@ -14,5 +14,5 @@ entry:
}
; 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
+; 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 d750d4f6b359..8f13d644a7ce 100644
--- a/test/wasm/signature-mismatch.ll
+++ b/test/wasm/signature-mismatch.ll
@@ -18,9 +18,9 @@ entry:
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
+; 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
+; 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-pointer.ll b/test/wasm/stack-pointer.ll
index 888c938881de..6851214fe91a 100644
--- a/test/wasm/stack-pointer.ll
+++ b/test/wasm/stack-pointer.ll
@@ -31,7 +31,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000001
@@ -50,7 +50,7 @@ entry:
; CHECK-NEXT: Body: 23808080800041106B1A41000B
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: linking
-; CHECK-NEXT: Version: 1
+; CHECK-NEXT: Version: 2
; CHECK-NEXT: SymbolTable:
; CHECK-NEXT: - Index: 0
; CHECK-NEXT: Kind: FUNCTION
diff --git a/test/wasm/strip-all.test b/test/wasm/strip-all.test
new file mode 100644
index 000000000000..7b7c25963bc7
--- /dev/null
+++ b/test/wasm/strip-all.test
@@ -0,0 +1,10 @@
+RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+RUN: wasm-ld --strip-all -o %t.wasm %t.start.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Test alias -s
+RUN: wasm-ld -s -o %t.wasm %t.start.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Check that there is no name section
+CHECK-NOT: Name: name
diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test
index be5ba700e258..6ee27f8c8a77 100644
--- a/test/wasm/strip-debug.test
+++ b/test/wasm/strip-debug.test
@@ -2,5 +2,9 @@ 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
+# Test alias -S
+RUN: wasm-ld -S -o %t.wasm %t.start.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
# Check that there is no name section
CHECK-NOT: Name: name
diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test
index ffa079ca638b..a36212f2c9e3 100644
--- a/test/wasm/undefined-entry.test
+++ b/test/wasm/undefined-entry.test
@@ -1,11 +1,9 @@
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 --allow-undefined -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
+CHECK: error: entry symbol not defined (pass --no-entry to supress): _start
+CHECK-CUSTOM: error: entry symbol not defined (pass --no-entry to supress): foo
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
index c13f5c1ae3f1..0b7d0c769d47 100644
--- a/test/wasm/undefined-weak-call.ll
+++ b/test/wasm/undefined-weak-call.ll
@@ -1,5 +1,5 @@
; RUN: llc -filetype=obj %s -o %t.o
-; RUN: wasm-ld --no-entry --print-gc-sections %t.o \
+; RUN: wasm-ld --entry=callWeakFuncs --print-gc-sections %t.o \
; RUN: -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-GC %s
; RUN: obj2yaml %t.wasm | FileCheck %s
@@ -45,7 +45,7 @@ define i32 @callWeakFuncs() {
; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1, 2 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000001
diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll
index 7d2161d2bcc6..1da979fc0764 100644
--- a/test/wasm/undefined.ll
+++ b/test/wasm/undefined.ll
@@ -1,10 +1,10 @@
; RUN: llc -filetype=obj %s -o %t.o
; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o
-; Fails due to undefined 'foo' and also 'baz'
+; Fails due to undefined 'foo'
; 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
+; CHECK-NOT: undefined symbol: baz
; Succeeds if we pass a file containing 'foo' as --allow-undefined-file.
; RUN: echo 'foo' > %t.txt
diff --git a/test/wasm/visibility-hidden.ll b/test/wasm/visibility-hidden.ll
index af973df0751a..b4fe0b53ba21 100644
--- a/test/wasm/visibility-hidden.ll
+++ b/test/wasm/visibility-hidden.ll
@@ -1,11 +1,18 @@
; RUN: llc -filetype=obj -o %t.o %s
; RUN: llc -filetype=obj %S/Inputs/hidden.ll -o %t2.o
+; RUN: rm -f %t2.a
; RUN: llvm-ar rcs %t2.a %t2.o
-; RUN: wasm-ld %t.o %t2.a -o %t.wasm
+
+; Test that symbols with hidden visitiblity are not export, even with
+; --export-dynamic
+; RUN: wasm-ld --export-dynamic %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.
+; Test that symbols with default visitiblity are not exported without
+; --export-dynamic
+; RUN: wasm-ld %t.o %t2.a -o %t.nodef.wasm
+; RUN: obj2yaml %t.nodef.wasm | FileCheck %s -check-prefix=NO-DEFAULT
+
target triple = "wasm32-unknown-unknown"
@@ -42,13 +49,30 @@ entry:
; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: archiveDefault
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 5
; CHECK-NEXT: - Type:
+
+
+; NO-DEFAULT: - Type: EXPORT
+; NO-DEFAULT-NEXT: Exports:
+; NO-DEFAULT-NEXT: - Name: memory
+; NO-DEFAULT-NEXT: Kind: MEMORY
+; NO-DEFAULT-NEXT: Index: 0
+; NO-DEFAULT-NEXT: - Name: __heap_base
+; NO-DEFAULT-NEXT: Kind: GLOBAL
+; NO-DEFAULT-NEXT: Index: 1
+; NO-DEFAULT-NEXT: - Name: __data_end
+; NO-DEFAULT-NEXT: Kind: GLOBAL
+; NO-DEFAULT-NEXT: Index: 2
+; NO-DEFAULT-NEXT: - Name: _start
+; NO-DEFAULT-NEXT: Kind: FUNCTION
+; NO-DEFAULT-NEXT: Index: 3
+; NO-DEFAULT-NEXT: - Type:
diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll
index 8b98f3347a1c..7fefad0fb04a 100644
--- a/test/wasm/weak-alias-overide.ll
+++ b/test/wasm/weak-alias-overide.ll
@@ -1,6 +1,6 @@
; 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: wasm-ld --export-dynamic %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
@@ -35,7 +35,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1, 1, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000003
@@ -74,12 +74,12 @@ entry:
; 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: alias_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Name: direct_fn
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 3
diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll
index 227906a55504..0c856e1eafa0 100644
--- a/test/wasm/weak-alias.ll
+++ b/test/wasm/weak-alias.ll
@@ -1,6 +1,6 @@
; 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: wasm-ld --export-dynamic %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
@@ -32,7 +32,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000002
@@ -170,7 +170,7 @@ entry:
; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ]
; RELOC-NEXT: - Type: TABLE
; RELOC-NEXT: Tables:
-; RELOC-NEXT: - ElemType: ANYFUNC
+; RELOC-NEXT: - ElemType: FUNCREF
; RELOC-NEXT: Limits:
; RELOC-NEXT: Flags: [ HAS_MAX ]
; RELOC-NEXT: Initial: 0x00000002
@@ -250,7 +250,7 @@ entry:
; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B
; RELOC-NEXT: - Type: CUSTOM
; RELOC-NEXT: Name: linking
-; RELOC-NEXT: Version: 1
+; RELOC-NEXT: Version: 2
; RELOC-NEXT: SymbolTable:
; RELOC-NEXT: - Index: 0
; RELOC-NEXT: Kind: FUNCTION
diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll
index bd45de39ca35..41ade7c1aa0e 100644
--- a/test/wasm/weak-symbols.ll
+++ b/test/wasm/weak-symbols.ll
@@ -1,7 +1,7 @@
; 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: wasm-ld --export-dynamic -o %t.wasm %t.o %t1.o %t2.o
; RUN: obj2yaml %t.wasm | FileCheck %s
target triple = "wasm32-unknown-unknown"
@@ -29,10 +29,10 @@ entry:
; CHECK-NEXT: ReturnType: I32
; CHECK-NEXT: ParamTypes:
; CHECK-NEXT: - Type: FUNCTION
-; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1 ]
+; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000002
@@ -59,7 +59,7 @@ entry:
; CHECK-NEXT: Mutable: false
; CHECK-NEXT: InitExpr:
; CHECK-NEXT: Opcode: I32_CONST
-; CHECK-NEXT: Value: 1032
+; CHECK-NEXT: Value: 1028
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Type: I32
; CHECK-NEXT: Mutable: false
@@ -91,7 +91,7 @@ entry:
; CHECK-NEXT: Index: 3
; CHECK-NEXT: - Name: exportWeak2
; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 5
+; CHECK-NEXT: Index: 4
; CHECK-NEXT: - Type: ELEM
; CHECK-NEXT: Segments:
; CHECK-NEXT: - Offset:
@@ -114,9 +114,6 @@ entry:
; CHECK-NEXT: Body: 4181808080000B
; CHECK-NEXT: - Index: 4
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 41020B
-; CHECK-NEXT: - Index: 5
-; CHECK-NEXT: Locals:
; CHECK-NEXT: Body: 4181808080000B
; CHECK-NEXT: - Type: DATA
; CHECK-NEXT: Segments:
@@ -125,7 +122,7 @@ entry:
; CHECK-NEXT: Offset:
; CHECK-NEXT: Opcode: I32_CONST
; CHECK-NEXT: Value: 1024
-; CHECK-NEXT: Content: '0100000002000000'
+; CHECK-NEXT: Content: '01000000'
; CHECK-NEXT: - Type: CUSTOM
; CHECK-NEXT: Name: name
; CHECK-NEXT: FunctionNames:
@@ -138,7 +135,5 @@ entry:
; 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-undefined.ll b/test/wasm/weak-undefined.ll
index 53b38bc32c3e..41e992e5ea47 100644
--- a/test/wasm/weak-undefined.ll
+++ b/test/wasm/weak-undefined.ll
@@ -22,7 +22,8 @@ define i32* @get_address_of_global_var() #0 {
define void @_start() #0 {
entry:
- %call = call i32* @get_address_of_global_var()
+ %call1 = call i32* @get_address_of_global_var()
+ %call2 = call i8* @get_address_of_foo()
ret void
}
@@ -42,7 +43,7 @@ entry:
; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 0 ]
; CHECK-NEXT: - Type: TABLE
; CHECK-NEXT: Tables:
-; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: - ElemType: FUNCREF
; CHECK-NEXT: Limits:
; CHECK-NEXT: Flags: [ HAS_MAX ]
; CHECK-NEXT: Initial: 0x00000001
@@ -84,12 +85,6 @@ entry:
; CHECK-NEXT: - Name: _start
; CHECK-NEXT: Kind: FUNCTION
; CHECK-NEXT: Index: 3
-; CHECK-NEXT: - Name: get_address_of_foo
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 1
-; CHECK-NEXT: - Name: get_address_of_global_var
-; CHECK-NEXT: Kind: FUNCTION
-; CHECK-NEXT: Index: 2
; CHECK-NEXT: - Type: CODE
; CHECK-NEXT: Functions:
; CHECK-NEXT: - Index: 0
@@ -103,5 +98,5 @@ entry:
; CHECK-NEXT: Body: 4180808080000B
; CHECK-NEXT: - Index: 3
; CHECK-NEXT: Locals:
-; CHECK-NEXT: Body: 1082808080001A0B
+; CHECK-NEXT: Body: 1082808080001A1081808080001A0B
; CHECK-NEXT: ...
diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp
index 4a8e3f7ec34a..c749d458a992 100644
--- a/tools/lld/lld.cpp
+++ b/tools/lld/lld.cpp
@@ -138,7 +138,7 @@ int main(int Argc, const char **Argv) {
return !wasm::link(Args, canExitEarly());
default:
die("lld is a generic driver.\n"
- "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld"
+ "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
" (WebAssembly) instead");
}
}
diff --git a/wasm/Config.h b/wasm/Config.h
index 76a780567072..0857a645f1e8 100644
--- a/wasm/Config.h
+++ b/wasm/Config.h
@@ -20,18 +20,22 @@ namespace wasm {
struct Configuration {
bool AllowUndefined;
- bool CompressRelocTargets;
+ bool CompressRelocations;
bool Demangle;
bool DisableVerify;
bool ExportAll;
+ bool ExportDynamic;
bool ExportTable;
bool GcSections;
bool ImportMemory;
+ bool SharedMemory;
bool ImportTable;
bool MergeDataSegments;
+ bool Pie;
bool PrintGcSections;
bool Relocatable;
bool SaveTemps;
+ bool Shared;
bool StripAll;
bool StripDebug;
bool StackFirst;
@@ -50,6 +54,9 @@ struct Configuration {
llvm::StringSet<> AllowUndefinedSymbols;
std::vector<llvm::StringRef> SearchPaths;
llvm::CachePruningPolicy ThinLTOCachePolicy;
+
+ // True if we are creating position-independent code.
+ bool Pic;
};
// The only instance of Configuration struct.
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 329b5ae80a9c..fab4c0c4ed8b 100644
--- a/wasm/Driver.cpp
+++ b/wasm/Driver.cpp
@@ -31,6 +31,7 @@
#define DEBUG_TYPE "lld"
using namespace llvm;
+using namespace llvm::object;
using namespace llvm::sys;
using namespace llvm::wasm;
@@ -78,7 +79,7 @@ private:
bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
- errorHandler().LogName = sys::path::filename(Args[0]);
+ errorHandler().LogName = args::getFilenameWithoutExe(Args[0]);
errorHandler().ErrorOS = &Error;
errorHandler().ColorDiagnostics = Error.has_colors();
errorHandler().ErrorLimitExceededMsg =
@@ -186,8 +187,7 @@ static void readImportFile(StringRef Filename) {
// 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::vector<MemoryBufferRef> static getArchiveMembers(MemoryBufferRef MB) {
std::unique_ptr<Archive> File =
CHECK(Archive::create(MB),
MB.getBufferIdentifier() + ": failed to parse archive");
@@ -205,8 +205,8 @@ std::vector<MemoryBufferRef> static getArchiveMembers(
V.push_back(MBRef);
}
if (Err)
- fatal(MB.getBufferIdentifier() + ": Archive::children failed: " +
- toString(std::move(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())
@@ -306,17 +306,14 @@ static void handleWeakUndefines() {
// 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;
+ assert(FuncSym->Signature);
+ const WasmSignature &Sig = *FuncSym->Signature;
// 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);
+ std::string SymName = toString(*Sym);
+ StringRef DebugName = Saver.save("undefined function " + SymName);
+ auto *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).
@@ -328,51 +325,24 @@ static void handleWeakUndefines() {
}
}
-// 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)) {
- Parser.PrintHelp(outs(), ArgsArr[0], "LLVM Linker", false);
- return;
- }
-
- // Handle --version
- if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
- outs() << getLLDVersion() << "\n";
- return;
- }
-
- // Parse and evaluate -mllvm options.
- std::vector<const char *> V;
- V.push_back("wasm-ld (LLVM option parsing)");
- for (auto *Arg : Args.filtered(OPT_mllvm))
- V.push_back(Arg->getValue());
- cl::ParseCommandLineOptions(V.size(), V.data());
-
- errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
-
+// 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(opt::InputArgList &Args) {
Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
+ Config->CompressRelocations = Args.hasArg(OPT_compress_relocations);
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->ExportDynamic = Args.hasFlag(OPT_export_dynamic,
+ OPT_no_export_dynamic, false);
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->SharedMemory = Args.hasArg(OPT_shared_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);
@@ -384,10 +354,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->MergeDataSegments =
Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
!Config->Relocatable);
+ Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false);
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->Shared = Args.hasArg(OPT_shared);
Config->StripAll = Args.hasArg(OPT_strip_all);
Config->StripDebug = Args.hasArg(OPT_strip_debug);
Config->StackFirst = Args.hasArg(OPT_stack_first);
@@ -404,8 +376,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->MaxMemory = args::getInteger(Args, OPT_max_memory, 0);
Config->ZStackSize =
args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);
+}
- Config->CompressRelocTargets = Config->Optimize > 0 && !Config->Relocatable;
+// Some command line options or some combinations of them are not allowed.
+// This function checks for such errors.
+static void checkOptions(opt::InputArgList &Args) {
+ if (!Config->StripDebug && !Config->StripAll && Config->CompressRelocations)
+ error("--compress-relocations is incompatible with output debug"
+ " information. Please pass --strip-debug or --strip-all");
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + Twine(Config->LTOO));
@@ -414,13 +392,8 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
- if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
- readImportFile(Arg->getValue());
-
- if (!Args.hasArg(OPT_INPUT)) {
- error("no input files");
- return;
- }
+ if (Config->Pie && Config->Shared)
+ error("-shared and -pie may not be used together");
if (Config->OutputFile.empty())
error("no output file specified");
@@ -433,46 +406,151 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
error("entry point specified for relocatable output file");
if (Config->GcSections)
error("-r and --gc-sections may not be used together");
+ if (Config->CompressRelocations)
+ error("-r -and --compress-relocations may not be used together");
if (Args.hasArg(OPT_undefined))
error("-r -and --undefined may not be used together");
+ if (Config->Pie)
+ error("-r and -pie may not be used together");
}
+}
- Symbol *EntrySym = nullptr;
- if (!Config->Relocatable) {
+// Force Sym to be entered in the output. Used for -u or equivalent.
+static Symbol *handleUndefined(StringRef Name) {
+ Symbol *Sym = Symtab->find(Name);
+ if (!Sym)
+ return nullptr;
+
+ // 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 (auto *LazySym = dyn_cast<LazySymbol>(Sym))
+ LazySym->fetch();
+
+ return Sym;
+}
+
+static UndefinedGlobal *
+createUndefinedGlobal(StringRef Name, llvm::wasm::WasmGlobalType *Type) {
+ auto *Sym =
+ cast<UndefinedGlobal>(Symtab->addUndefinedGlobal(Name, 0, nullptr, Type));
+ Config->AllowUndefinedSymbols.insert(Sym->getName());
+ Sym->IsUsedInRegularObj = true;
+ return Sym;
+}
+
+// Create ABI-defined synthetic symbols
+static void createSyntheticSymbols() {
+ static WasmSignature NullSignature = {{}, {}};
+ static llvm::wasm::WasmGlobalType GlobalTypeI32 = {WASM_TYPE_I32, false};
+ static llvm::wasm::WasmGlobalType MutableGlobalTypeI32 = {WASM_TYPE_I32,
+ true};
+
+ if (!Config->Relocatable)
+ WasmSym::CallCtors = Symtab->addSyntheticFunction(
+ "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN,
+ make<SyntheticFunction>(NullSignature, "__wasm_call_ctors"));
+
+ // The __stack_pointer is imported in the shared library case, and exported
+ // in the non-shared (executable) case.
+ if (Config->Shared) {
+ WasmSym::StackPointer =
+ createUndefinedGlobal("__stack_pointer", &MutableGlobalTypeI32);
+ } else {
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);
+ auto *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"));
+ // For non-PIC code
// 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);
+ // These two synthetic symbols exist purely for the embedder so we always
+ // want to export them.
+ WasmSym::HeapBase->ForceExport = true;
+ WasmSym::DataEnd->ForceExport = true;
+ }
+
+ if (Config->Pic) {
+ // For PIC code, we import two global variables (__memory_base and
+ // __table_base) from the environment and use these as the offset at
+ // which to load our static data and function table.
+ // See:
+ // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+ WasmSym::MemoryBase =
+ createUndefinedGlobal("__memory_base", &GlobalTypeI32);
+ WasmSym::TableBase = createUndefinedGlobal("__table_base", &GlobalTypeI32);
+ WasmSym::MemoryBase->markLive();
+ WasmSym::TableBase->markLive();
+ }
+
+ WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol(
+ "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN);
+}
+
+void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
+ WasmOptTable Parser;
+ opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+
+ // Handle --help
+ if (Args.hasArg(OPT_help)) {
+ Parser.PrintHelp(outs(),
+ (std::string(ArgsArr[0]) + " [options] file...").c_str(),
+ "LLVM Linker", false);
+ return;
+ }
- // Handle the `--undefined <sym>` options.
- for (auto *Arg : Args.filtered(OPT_undefined))
- addUndefined(Arg->getValue());
+ // Handle --version
+ if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
+ outs() << getLLDVersion() << "\n";
+ return;
}
+ // Parse and evaluate -mllvm options.
+ std::vector<const char *> V;
+ V.push_back("wasm-ld (LLVM option parsing)");
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ V.push_back(Arg->getValue());
+ cl::ParseCommandLineOptions(V.size(), V.data());
+
+ errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20);
+
+ setConfigs(Args);
+ checkOptions(Args);
+
+ if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
+ readImportFile(Arg->getValue());
+
+ if (!Args.hasArg(OPT_INPUT)) {
+ error("no input files");
+ return;
+ }
+
+ Config->Pic = Config->Pie || Config->Shared;
+
+ if (Config->Pic) {
+ if (Config->ExportTable)
+ error("-shared/-pie is incompatible with --export-table");
+ Config->ImportTable = true;
+ }
+
+ if (Config->Shared) {
+ Config->ExportDynamic = true;
+ Config->AllowUndefined = true;
+ }
+
+ if (!Config->Relocatable)
+ createSyntheticSymbols();
+
createFiles(Args);
if (errorCount())
return;
@@ -484,44 +562,46 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (errorCount())
return;
- // Add synthetic dummies for weak undefined functions.
- if (!Config->Relocatable)
- handleWeakUndefines();
+ // Handle the `--undefined <sym>` options.
+ for (auto *Arg : Args.filtered(OPT_undefined))
+ handleUndefined(Arg->getValue());
- // Handle --export.
+ // Handle the `--export <sym>` options
+ // This works like --undefined but also exports the symbol if its found
for (auto *Arg : Args.filtered(OPT_export)) {
- StringRef Name = Arg->getValue();
- Symbol *Sym = Symtab->find(Name);
+ Symbol *Sym = handleUndefined(Arg->getValue());
if (Sym && Sym->isDefined())
Sym->ForceExport = true;
else if (!Config->AllowUndefined)
- error("symbol exported via --export not found: " + Name);
+ error(Twine("symbol exported via --export not found: ") +
+ Arg->getValue());
}
- // Do link-time optimization if given files are LLVM bitcode files.
- // This compiles bitcode files into real object files.
- Symtab->addCombinedLTOObject();
- if (errorCount())
- return;
+ Symbol *EntrySym = nullptr;
+ if (!Config->Relocatable) {
+ // Add synthetic dummies for weak undefined functions.
+ handleWeakUndefines();
- // Make sure we have resolved all symbols.
- if (!Config->Relocatable && !Config->AllowUndefined) {
- Symtab->reportRemainingUndefines();
- } else {
- // 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("symbol forced with --undefined not found: " + Sym->getName());
+ if (!Config->Shared && !Config->Entry.empty()) {
+ EntrySym = handleUndefined(Config->Entry);
+ if (EntrySym && EntrySym->isDefined())
+ EntrySym->ForceExport = true;
+ else
+ error("entry symbol not defined (pass --no-entry to supress): " +
+ Config->Entry);
}
- if (EntrySym && !EntrySym->isDefined())
- error("entry symbol not defined (pass --no-entry to supress): " +
- EntrySym->getName());
+
+ // Make sure we have resolved all symbols.
+ if (!Config->AllowUndefined)
+ Symtab->reportRemainingUndefines();
}
+
+ if (errorCount())
+ return;
+
+ // Do link-time optimization if given files are LLVM bitcode files.
+ // This compiles bitcode files into real object files.
+ Symtab->addCombinedLTOObject();
if (errorCount())
return;
diff --git a/wasm/InputChunks.cpp b/wasm/InputChunks.cpp
index fcefac7d99b8..1145c670253c 100644
--- a/wasm/InputChunks.cpp
+++ b/wasm/InputChunks.cpp
@@ -25,7 +25,9 @@ using namespace lld::wasm;
static StringRef ReloctTypeToString(uint8_t RelocType) {
switch (RelocType) {
-#define WASM_RELOC(NAME, REL) case REL: return #NAME;
+#define WASM_RELOC(NAME, REL) \
+ case REL: \
+ return #NAME;
#include "llvm/BinaryFormat/WasmRelocs.def"
#undef WASM_RELOC
}
@@ -43,16 +45,6 @@ StringRef InputChunk::getComdatName() const {
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;
@@ -63,6 +55,7 @@ void InputChunk::verifyRelocTargets() const {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
ExistingValue = decodeULEB128(Loc, &BytesRead);
break;
@@ -119,6 +112,7 @@ void InputChunk::writeTo(uint8_t *Buf) const {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
encodeULEB128(Value, Loc, 5);
break;
@@ -188,6 +182,7 @@ static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel,
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
return encodeULEB128(Value, Buf);
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
@@ -203,6 +198,7 @@ static unsigned getRelocWidthPadded(const WasmRelocation &Rel) {
case R_WEBASSEMBLY_TYPE_INDEX_LEB:
case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB:
case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
@@ -228,7 +224,7 @@ static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) {
// 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)
+ if (!File || !Config->CompressRelocations)
return;
LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n");
@@ -242,7 +238,7 @@ void InputFunction::calculateSize() {
uint32_t End = Start + Function->Size;
uint32_t LastRelocEnd = Start + FunctionSizeLength;
- for (WasmRelocation &Rel : Relocations) {
+ for (const WasmRelocation &Rel : Relocations) {
LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n");
CompressedFuncSize += Rel.Offset - LastRelocEnd;
CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel));
@@ -263,11 +259,12 @@ void InputFunction::calculateSize() {
// 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)
+ if (!File || !Config->CompressRelocations)
return InputChunk::writeTo(Buf);
Buf += OutputOffset;
- uint8_t *Orig = Buf; (void)Orig;
+ uint8_t *Orig = Buf;
+ (void)Orig;
const uint8_t *SecStart = File->CodeSection->Content.data();
const uint8_t *FuncStart = SecStart + getInputSectionOffset();
diff --git a/wasm/InputChunks.h b/wasm/InputChunks.h
index 526e29870b21..a3bcbb266ec5 100644
--- a/wasm/InputChunks.h
+++ b/wasm/InputChunks.h
@@ -24,18 +24,9 @@
#include "Config.h"
#include "InputFiles.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.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 {
@@ -49,17 +40,18 @@ public:
Kind kind() const { return SectionKind; }
virtual uint32_t getSize() const { return data().size(); }
-
- void copyRelocations(const WasmSection &Section);
+ virtual uint32_t getInputSize() const { return getSize(); };
virtual void writeTo(uint8_t *SectionStart) const;
ArrayRef<WasmRelocation> getRelocations() const { return Relocations; }
+ void setRelocations(ArrayRef<WasmRelocation> Rs) { Relocations = Rs; }
virtual StringRef getName() const = 0;
virtual StringRef getDebugName() const = 0;
virtual uint32_t getComdat() const = 0;
StringRef getComdatName() const;
+ virtual uint32_t getInputSectionOffset() const = 0;
size_t NumRelocations() const { return Relocations.size(); }
void writeRelocations(llvm::raw_ostream &OS) const;
@@ -77,14 +69,12 @@ protected:
: 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;
+ ArrayRef<WasmRelocation> Relocations;
Kind SectionKind;
};
@@ -107,15 +97,15 @@ public:
StringRef getName() const override { return Segment.Data.Name; }
StringRef getDebugName() const override { return StringRef(); }
uint32_t getComdat() const override { return Segment.Data.Comdat; }
+ uint32_t getInputSectionOffset() const override {
+ return Segment.SectionOffset;
+ }
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;
};
@@ -139,15 +129,19 @@ public:
uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); }
uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; }
uint32_t getSize() const override {
- if (Config->CompressRelocTargets && File) {
+ if (Config->CompressRelocations && File) {
assert(CompressedSize);
return CompressedSize;
}
return data().size();
}
+ uint32_t getInputSize() const override { return Function->Size; }
uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); }
bool hasFunctionIndex() const { return FunctionIndex.hasValue(); }
void setFunctionIndex(uint32_t Index);
+ uint32_t getInputSectionOffset() const override {
+ return Function->CodeSectionOffset;
+ }
uint32_t getTableIndex() const { return TableIndex.getValue(); }
bool hasTableIndex() const { return TableIndex.hasValue(); }
void setTableIndex(uint32_t Index);
@@ -162,17 +156,11 @@ public:
protected:
ArrayRef<uint8_t> data() const override {
- assert(!Config->CompressRelocTargets);
+ assert(!Config->CompressRelocations);
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;
diff --git a/wasm/InputEvent.h b/wasm/InputEvent.h
new file mode 100644
index 000000000000..d7c12627bd3d
--- /dev/null
+++ b/wasm/InputEvent.h
@@ -0,0 +1,63 @@
+//===- InputEvent.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Wasm events are features that suspend the current execution and transfer the
+// control flow to a corresponding handler. Currently the only supported event
+// kind is exceptions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_EVENT_H
+#define LLD_WASM_INPUT_EVENT_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+namespace lld {
+namespace wasm {
+
+// Represents a single Wasm Event within an input file. These are combined to
+// form the final EVENTS section.
+class InputEvent {
+public:
+ InputEvent(const WasmSignature &S, const WasmEvent &E, ObjFile *F)
+ : File(F), Event(E), Signature(S), Live(!Config->GcSections) {}
+
+ StringRef getName() const { return Event.SymbolName; }
+ const WasmEventType &getType() const { return Event.Type; }
+
+ uint32_t getEventIndex() const { return EventIndex.getValue(); }
+ bool hasEventIndex() const { return EventIndex.hasValue(); }
+ void setEventIndex(uint32_t Index) {
+ assert(!hasEventIndex());
+ EventIndex = Index;
+ }
+
+ ObjFile *File;
+ WasmEvent Event;
+ const WasmSignature &Signature;
+
+ bool Live = false;
+
+protected:
+ llvm::Optional<uint32_t> EventIndex;
+};
+
+} // namespace wasm
+
+inline std::string toString(const wasm::InputEvent *E) {
+ return (toString(E->File) + ":(" + E->getName() + ")").str();
+}
+
+} // namespace lld
+
+#endif // LLD_WASM_INPUT_EVENT_H
diff --git a/wasm/InputFiles.cpp b/wasm/InputFiles.cpp
index 53a24c3cffd4..e5da23db3773 100644
--- a/wasm/InputFiles.cpp
+++ b/wasm/InputFiles.cpp
@@ -10,6 +10,7 @@
#include "InputFiles.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputEvent.h"
#include "InputGlobal.h"
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
@@ -57,12 +58,13 @@ 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()));
+ "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals()) +
+ "\n Event Imports : " + Twine(WasmObj->getNumImportedEvents()));
}
// 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).
+// symbol/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]);
@@ -94,16 +96,17 @@ 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];
+ 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];
+ const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
if (Sym.isUndefined())
return 0;
- const WasmSegment& Segment = WasmObj->dataSegments()[Sym.Info.DataRef.Segment];
+ const WasmSegment &Segment =
+ WasmObj->dataSegments()[Sym.Info.DataRef.Segment];
return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset +
Reloc.Addend;
}
@@ -118,8 +121,9 @@ uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const {
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];
+ case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB: {
+ const WasmSymbol &Sym = WasmObj->syms()[Reloc.Index];
return Sym.Info.ElementIndex;
}
default:
@@ -146,10 +150,13 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
+ case R_WEBASSEMBLY_EVENT_INDEX_LEB:
+ return getEventSymbol(Reloc.Index)->getEventIndex();
case R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
- return Sym->Function->OutputOffset +
- Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
+ if (Sym->isLive())
+ return Sym->Function->OutputOffset +
+ Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
}
return 0;
case R_WEBASSEMBLY_SECTION_OFFSET_I32:
@@ -159,6 +166,37 @@ uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
}
}
+template <class T>
+static void setRelocs(const std::vector<T *> &Chunks,
+ const WasmSection *Section) {
+ if (!Section)
+ return;
+
+ ArrayRef<WasmRelocation> Relocs = Section->Relocations;
+ assert(std::is_sorted(Relocs.begin(), Relocs.end(),
+ [](const WasmRelocation &R1, const WasmRelocation &R2) {
+ return R1.Offset < R2.Offset;
+ }));
+ assert(std::is_sorted(
+ Chunks.begin(), Chunks.end(), [](InputChunk *C1, InputChunk *C2) {
+ return C1->getInputSectionOffset() < C2->getInputSectionOffset();
+ }));
+
+ auto RelocsNext = Relocs.begin();
+ auto RelocsEnd = Relocs.end();
+ auto RelocLess = [](const WasmRelocation &R, uint32_t Val) {
+ return R.Offset < Val;
+ };
+ for (InputChunk *C : Chunks) {
+ auto RelocsStart = std::lower_bound(RelocsNext, RelocsEnd,
+ C->getInputSectionOffset(), RelocLess);
+ RelocsNext = std::lower_bound(
+ RelocsStart, RelocsEnd, C->getInputSectionOffset() + C->getInputSize(),
+ RelocLess);
+ C->setRelocations(ArrayRef<WasmRelocation>(RelocsStart, RelocsNext));
+ }
+}
+
void ObjFile::parse() {
// Parse a memory buffer as a wasm file.
LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
@@ -200,7 +238,7 @@ void ObjFile::parse() {
DataSection = &Section;
} else if (Section.Type == WASM_SEC_CUSTOM) {
CustomSections.emplace_back(make<InputSection>(Section, this));
- CustomSections.back()->copyRelocations(Section);
+ CustomSections.back()->setRelocations(Section.Relocations);
CustomSectionsByIndex[SectionIndex] = CustomSections.back();
}
SectionIndex++;
@@ -215,11 +253,9 @@ void ObjFile::parse() {
UsedComdats[I] = Symtab->addComdat(Comdats[I]);
// Populate `Segments`.
- for (const WasmSegment &S : WasmObj->dataSegments()) {
- InputSegment *Seg = make<InputSegment>(S, this);
- Seg->copyRelocations(*DataSection);
- Segments.emplace_back(Seg);
- }
+ for (const WasmSegment &S : WasmObj->dataSegments())
+ Segments.emplace_back(make<InputSegment>(S, this));
+ setRelocs(Segments, DataSection);
// Populate `Functions`.
ArrayRef<WasmFunction> Funcs = WasmObj->functions();
@@ -227,17 +263,19 @@ void ObjFile::parse() {
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);
- }
+ for (size_t I = 0, E = Funcs.size(); I != E; ++I)
+ Functions.emplace_back(
+ make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this));
+ setRelocs(Functions, CodeSection);
// Populate `Globals`.
for (const WasmGlobal &G : WasmObj->globals())
Globals.emplace_back(make<InputGlobal>(G, this));
+ // Populate `Events`.
+ for (const WasmEvent &E : WasmObj->events())
+ Events.emplace_back(make<InputEvent>(Types[E.Type.SigIndex], E, this));
+
// Populate `Symbols` based on the WasmSymbols in the object.
Symbols.reserve(WasmObj->getNumberOfSymbols());
for (const SymbolRef &Sym : WasmObj->symbols()) {
@@ -264,6 +302,10 @@ GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
return cast<GlobalSymbol>(Symbols[Index]);
}
+EventSymbol *ObjFile::getEventSymbol(uint32_t Index) const {
+ return cast<EventSymbol>(Symbols[Index]);
+}
+
SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const {
return cast<SectionSymbol>(Symbols[Index]);
}
@@ -318,6 +360,13 @@ Symbol *ObjFile::createDefined(const WasmSymbol &Sym) {
assert(Sym.isBindingLocal());
return make<SectionSymbol>(Name, Flags, Section, this);
}
+ case WASM_SYMBOL_TYPE_EVENT: {
+ InputEvent *Event =
+ Events[Sym.Info.ElementIndex - WasmObj->getNumImportedEvents()];
+ if (Sym.isBindingLocal())
+ return make<DefinedEvent>(Name, Flags, this, Event);
+ return Symtab->addDefinedEvent(Name, Flags, this, Event);
+ }
}
llvm_unreachable("unknown symbol kind");
}
@@ -328,7 +377,7 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
switch (Sym.Info.Kind) {
case WASM_SYMBOL_TYPE_FUNCTION:
- return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType);
+ return Symtab->addUndefinedFunction(Name, Flags, this, Sym.Signature);
case WASM_SYMBOL_TYPE_DATA:
return Symtab->addUndefinedData(Name, Flags, this);
case WASM_SYMBOL_TYPE_GLOBAL:
diff --git a/wasm/InputFiles.h b/wasm/InputFiles.h
index ec77446e6308..bcda9cc8ee92 100644
--- a/wasm/InputFiles.h
+++ b/wasm/InputFiles.h
@@ -20,21 +20,6 @@
#include "llvm/Support/MemoryBuffer.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 {
@@ -42,6 +27,7 @@ class InputChunk;
class InputFunction;
class InputSegment;
class InputGlobal;
+class InputEvent;
class InputSection;
class InputFile {
@@ -84,12 +70,12 @@ public:
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
- void addMember(const Archive::Symbol *Sym);
+ void addMember(const llvm::object::Archive::Symbol *Sym);
void parse() override;
private:
- std::unique_ptr<Archive> File;
+ std::unique_ptr<llvm::object::Archive> File;
llvm::DenseSet<uint64_t> Seen;
};
@@ -123,6 +109,7 @@ public:
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
std::vector<InputGlobal *> Globals;
+ std::vector<InputEvent *> Events;
std::vector<InputSection *> CustomSections;
llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex;
@@ -131,6 +118,7 @@ public:
DataSymbol *getDataSymbol(uint32_t Index) const;
GlobalSymbol *getGlobalSymbol(uint32_t Index) const;
SectionSymbol *getSectionSymbol(uint32_t Index) const;
+ EventSymbol *getEventSymbol(uint32_t Index) const;
private:
Symbol *createDefined(const WasmSymbol &Sym);
diff --git a/wasm/InputGlobal.h b/wasm/InputGlobal.h
index 37d0ab903706..3b20600b22e8 100644
--- a/wasm/InputGlobal.h
+++ b/wasm/InputGlobal.h
@@ -16,9 +16,6 @@
#include "lld/Common/ErrorHandler.h"
#include "llvm/Object/Wasm.h"
-using llvm::wasm::WasmGlobal;
-using llvm::wasm::WasmInitExpr;
-
namespace lld {
namespace wasm {
diff --git a/wasm/LTO.cpp b/wasm/LTO.cpp
index f15551da8b80..96a947e29d41 100644
--- a/wasm/LTO.cpp
+++ b/wasm/LTO.cpp
@@ -36,8 +36,6 @@
#include <vector>
using namespace llvm;
-using namespace llvm::object;
-
using namespace lld;
using namespace lld::wasm;
@@ -55,6 +53,14 @@ static std::unique_ptr<lto::LTO> createLTO() {
C.DisableVerify = Config->DisableVerify;
C.DiagHandler = diagnosticHandler;
C.OptLevel = Config->LTOO;
+ C.MAttrs = GetMAttrs();
+
+ if (Config->Relocatable)
+ C.RelocModel = None;
+ else if (Config->Pic)
+ C.RelocModel = Reloc::PIC_;
+ else
+ C.RelocModel = Reloc::Static;
if (Config->SaveTemps)
checkError(C.addSaveTemps(Config->OutputFile.str() + ".",
@@ -72,10 +78,11 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
static void undefine(Symbol *S) {
- if (isa<DefinedFunction>(S))
- replaceSymbol<UndefinedFunction>(S, S->getName(), 0);
+ if (auto F = dyn_cast<DefinedFunction>(S))
+ replaceSymbol<UndefinedFunction>(F, F->getName(), 0, F->getFile(),
+ F->Signature);
else if (isa<DefinedData>(S))
- replaceSymbol<UndefinedData>(S, S->getName(), 0);
+ replaceSymbol<UndefinedData>(S, S->getName(), 0, S->getFile());
else
llvm_unreachable("unexpected symbol kind");
}
diff --git a/wasm/MarkLive.cpp b/wasm/MarkLive.cpp
index dfaa712c3296..3bbd1148f6ad 100644
--- a/wasm/MarkLive.cpp
+++ b/wasm/MarkLive.cpp
@@ -22,6 +22,7 @@
#include "MarkLive.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputEvent.h"
#include "InputGlobal.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -30,8 +31,6 @@
using namespace llvm;
using namespace llvm::wasm;
-using namespace lld;
-using namespace lld::wasm;
void lld::wasm::markLive() {
if (!Config->GcSections)
@@ -107,6 +106,9 @@ void lld::wasm::markLive() {
for (InputGlobal *G : Obj->Globals)
if (!G->Live)
message("removing unused section " + toString(G));
+ for (InputEvent *E : Obj->Events)
+ if (!E->Live)
+ message("removing unused section " + toString(E));
}
for (InputChunk *C : Symtab->SyntheticFunctions)
if (!C->Live)
diff --git a/wasm/Options.td b/wasm/Options.td
index 43588a830e31..3ed55b4bcda0 100644
--- a/wasm/Options.td
+++ b/wasm/Options.td
@@ -6,9 +6,10 @@ 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>;
}
multiclass B<string name, string help1, string help2> {
@@ -16,17 +17,24 @@ multiclass B<string name, string help1, string help2> {
def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>;
}
-// The follow flags are shared with the ELF linker
+// The following 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; one of 'always', 'never', 'auto'">;
+def compress_relocations: F<"compress-relocations">,
+ HelpText<"Compress the relocation targets in the code section.">;
+
defm demangle: B<"demangle",
"Demangle symbol names",
"Do not demangle symbol names">;
+defm export_dynamic: B<"export-dynamic",
+ "Put symbols in the dynamic symbol table",
+ "Do not put symbols in the dynamic symbol table (default)">;
+
def entry: S<"entry">, MetaVarName<"<entry>">,
HelpText<"Name of entry point symbol">;
@@ -67,20 +75,25 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">;
+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">;
def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+def shared: F<"shared">, HelpText<"Build a shared object">;
+
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">;
+defm undefined: Eq<"undefined", "Force undefined symbol during linking">;
def v: Flag<["-"], "v">, HelpText<"Display the version number">;
@@ -102,8 +115,7 @@ def allow_undefined_file: J<"allow-undefined-file=">,
def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">,
Alias<allow_undefined_file>;
-defm export: Eq<"export">,
- HelpText<"Force a symbol to be exported">;
+defm export: Eq<"export", "Force a symbol to be exported">;
def export_all: F<"export-all">,
HelpText<"Export all symbols (normally combined with --no-gc-sections)">;
@@ -117,6 +129,9 @@ def global_base: J<"global-base=">,
def import_memory: F<"import-memory">,
HelpText<"Import memory from the environment">;
+def shared_memory: F<"shared-memory">,
+ HelpText<"Use shared linear memory">;
+
def import_table: F<"import-table">,
HelpText<"Import function table from the environment">;
@@ -137,12 +152,15 @@ defm whole_archive: B<"whole-archive",
"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_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
+def: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def: J<"entry=">, Alias<entry>;
+def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">;
+def: Flag<["-"], "i">, Alias<initial_memory>;
+def: Flag<["-"], "m">, Alias<max_memory>;
+def: Flag<["-"], "r">, Alias<relocatable>;
+def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">;
+def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">;
+def: JoinedOrSeparate<["-"], "u">, Alias<undefined>;
// LTO-related options.
def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
@@ -153,6 +171,5 @@ 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">;
+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">;
diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp
index 256a9884f947..4123d63b7466 100644
--- a/wasm/OutputSections.cpp
+++ b/wasm/OutputSections.cpp
@@ -40,6 +40,8 @@ static StringRef sectionTypeToString(uint32_t SectionType) {
return "MEMORY";
case WASM_SEC_GLOBAL:
return "GLOBAL";
+ case WASM_SEC_EVENT:
+ return "EVENT";
case WASM_SEC_EXPORT:
return "EXPORT";
case WASM_SEC_START:
@@ -136,9 +138,17 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
for (OutputSegment *Segment : Segments) {
raw_string_ostream OS(Segment->Header);
writeUleb128(OS, 0, "memory index");
- writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
- writeSleb128(OS, Segment->StartVA, "memory offset");
- writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
+ WasmInitExpr InitExpr;
+ if (Config->Pic) {
+ assert(Segments.size() <= 1 &&
+ "Currenly only a single data segment is supported in PIC mode");
+ InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
+ InitExpr.Value.Global = WasmSym::MemoryBase->getGlobalIndex();
+ } else {
+ InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ InitExpr.Value.Int32 = Segment->StartVA;
+ }
+ writeInitExpr(OS, InitExpr);
writeUleb128(OS, Segment->Size, "segment size");
OS.flush();
diff --git a/wasm/OutputSections.h b/wasm/OutputSections.h
index 189d6507c4b3..6c5baa309a98 100644
--- a/wasm/OutputSections.h
+++ b/wasm/OutputSections.h
@@ -13,11 +13,9 @@
#include "InputChunks.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/LLVM.h"
#include "llvm/ADT/DenseMap.h"
-using llvm::raw_ostream;
-using llvm::raw_string_ostream;
-
namespace lld {
namespace wasm {
@@ -82,7 +80,7 @@ public:
std::string Body;
protected:
- raw_string_ostream BodyOutputStream;
+ llvm::raw_string_ostream BodyOutputStream;
};
class CodeSection : public OutputSection {
@@ -113,7 +111,7 @@ protected:
size_t BodySize = 0;
};
-// Represents a custom section in the output file. Wasm custom sections are
+// 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
diff --git a/wasm/OutputSegment.h b/wasm/OutputSegment.h
index d5c89cd19f4c..a982282dac10 100644
--- a/wasm/OutputSegment.h
+++ b/wasm/OutputSegment.h
@@ -26,7 +26,7 @@ public:
void addInputSegment(InputSegment *InSeg) {
Alignment = std::max(Alignment, InSeg->getAlignment());
InputSegments.push_back(InSeg);
- Size = llvm::alignTo(Size, InSeg->getAlignment());
+ Size = llvm::alignTo(Size, 1 << InSeg->getAlignment());
InSeg->OutputSeg = this;
InSeg->OutputSegmentOffset = Size;
Size += InSeg->getSize();
diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp
index e1ba23769738..c7983196db36 100644
--- a/wasm/SymbolTable.cpp
+++ b/wasm/SymbolTable.cpp
@@ -10,6 +10,7 @@
#include "SymbolTable.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputEvent.h"
#include "InputGlobal.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
@@ -20,6 +21,7 @@
using namespace llvm;
using namespace llvm::wasm;
+using namespace llvm::object;
using namespace lld;
using namespace lld::wasm;
@@ -60,7 +62,6 @@ void SymbolTable::addCombinedLTOObject() {
}
void SymbolTable::reportRemainingUndefines() {
- SetVector<Symbol *> Undefs;
for (Symbol *Sym : SymVector) {
if (!Sym->isUndefined() || Sym->isWeak())
continue;
@@ -68,34 +69,26 @@ void SymbolTable::reportRemainingUndefines() {
continue;
if (!Sym->IsUsedInRegularObj)
continue;
- Undefs.insert(Sym);
+ error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym));
}
-
- if (Undefs.empty())
- return;
-
- for (ObjFile *File : ObjectFiles)
- for (Symbol *Sym : File->getSymbols())
- if (Undefs.count(Sym))
- error(toString(File) + ": undefined symbol: " + toString(*Sym));
-
- for (Symbol *Sym : Undefs)
- if (!Sym->getFile())
- error("undefined symbol: " + toString(*Sym));
}
Symbol *SymbolTable::find(StringRef Name) {
return SymMap.lookup(CachedHashStringRef(Name));
}
-std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name, InputFile *File) {
+ bool Inserted = false;
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
- if (Sym)
- return {Sym, false};
- Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
- Sym->IsUsedInRegularObj = false;
- SymVector.emplace_back(Sym);
- return {Sym, true};
+ if (!Sym) {
+ Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
+ Sym->IsUsedInRegularObj = false;
+ SymVector.emplace_back(Sym);
+ Inserted = true;
+ }
+ if (!File || File->kind() == InputFile::ObjectKind)
+ Sym->IsUsedInRegularObj = true;
+ return {Sym, Inserted};
}
static void reportTypeError(const Symbol *Existing, const InputFile *File,
@@ -106,6 +99,8 @@ static void reportTypeError(const Symbol *Existing, const InputFile *File,
" 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 checkFunctionType(Symbol *Existing, const InputFile *File,
const WasmSignature *NewSig) {
auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
@@ -117,9 +112,9 @@ static void checkFunctionType(Symbol *Existing, const InputFile *File,
if (!NewSig)
return;
- const WasmSignature *OldSig = ExistingFunction->FunctionType;
+ const WasmSignature *OldSig = ExistingFunction->Signature;
if (!OldSig) {
- ExistingFunction->FunctionType = NewSig;
+ ExistingFunction->Signature = NewSig;
return;
}
@@ -130,8 +125,6 @@ static void checkFunctionType(Symbol *Existing, const InputFile *File,
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 checkGlobalType(const Symbol *Existing, const InputFile *File,
const WasmGlobalType *NewType) {
if (!isa<GlobalSymbol>(Existing)) {
@@ -147,6 +140,28 @@ static void checkGlobalType(const Symbol *Existing, const InputFile *File,
}
}
+static void checkEventType(const Symbol *Existing, const InputFile *File,
+ const WasmEventType *NewType,
+ const WasmSignature *NewSig) {
+ auto ExistingEvent = dyn_cast<EventSymbol>(Existing);
+ if (!isa<EventSymbol>(Existing)) {
+ reportTypeError(Existing, File, WASM_SYMBOL_TYPE_EVENT);
+ return;
+ }
+
+ const WasmEventType *OldType = cast<EventSymbol>(Existing)->getEventType();
+ const WasmSignature *OldSig = ExistingEvent->Signature;
+ if (NewType->Attribute != OldType->Attribute)
+ error("Event type mismatch: " + Existing->getName() + "\n>>> defined as " +
+ toString(*OldType) + " in " + toString(Existing->getFile()) +
+ "\n>>> defined as " + toString(*NewType) + " in " + toString(File));
+ if (*NewSig != *OldSig)
+ warn("Event signature mismatch: " + Existing->getName() +
+ "\n>>> defined as " + toString(*OldSig) + " in " +
+ toString(Existing->getFile()) + "\n>>> defined as " +
+ toString(*NewSig) + " in " + toString(File));
+}
+
static void checkDataType(const Symbol *Existing, const InputFile *File) {
if (!isa<DataSymbol>(Existing))
reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA);
@@ -158,15 +173,15 @@ DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
assert(!find(Name));
SyntheticFunctions.emplace_back(Function);
- return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags,
- nullptr, Function);
+ return replaceSymbol<DefinedFunction>(insert(Name, nullptr).first, Name,
+ Flags, nullptr, Function);
}
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);
+ return replaceSymbol<DefinedData>(insert(Name, nullptr).first, Name, Flags);
}
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
@@ -175,8 +190,8 @@ DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags,
<< "\n");
assert(!find(Name));
SyntheticGlobals.emplace_back(Global);
- return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr,
- Global);
+ return replaceSymbol<DefinedGlobal>(insert(Name, nullptr).first, Name, Flags,
+ nullptr, Global);
}
static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
@@ -210,13 +225,12 @@ static bool shouldReplace(const Symbol *Existing, InputFile *NewFile,
Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
InputFile *File,
InputFunction *Function) {
- LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << " ["
+ << (Function ? toString(Function->Signature) : "none")
+ << "]\n");
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
-
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
@@ -226,8 +240,16 @@ Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags,
if (Function)
checkFunctionType(S, File, &Function->Signature);
- if (shouldReplace(S, File, Flags))
- replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
+ if (shouldReplace(S, File, Flags)) {
+ // If the new defined function doesn't have signture (i.e. bitcode
+ // functions) but the old symbols does then preserve the old signature
+ const WasmSignature *OldSig = nullptr;
+ if (auto* F = dyn_cast<FunctionSymbol>(S))
+ OldSig = F->Signature;
+ auto NewSym = replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function);
+ if (!NewSym->Signature)
+ NewSym->Signature = OldSig;
+ }
return S;
}
@@ -238,10 +260,7 @@ Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
<< "\n");
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
-
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size);
@@ -258,12 +277,10 @@ Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags,
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 (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted || S->isLazy()) {
replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global);
@@ -277,17 +294,35 @@ Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags,
return S;
}
+Symbol *SymbolTable::addDefinedEvent(StringRef Name, uint32_t Flags,
+ InputFile *File, InputEvent *Event) {
+ LLVM_DEBUG(dbgs() << "addDefinedEvent:" << Name << "\n");
+
+ Symbol *S;
+ bool WasInserted;
+ std::tie(S, WasInserted) = insert(Name, File);
+
+ if (WasInserted || S->isLazy()) {
+ replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
+ return S;
+ }
+
+ checkEventType(S, File, &Event->getType(), &Event->Signature);
+
+ if (shouldReplace(S, File, Flags))
+ replaceSymbol<DefinedEvent>(S, Name, Flags, File, Event);
+ return S;
+}
+
Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags,
InputFile *File,
const WasmSignature *Sig) {
- LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
+ LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name <<
+ " [" << (Sig ? toString(*Sig) : "none") << "]\n");
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
-
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted)
replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig);
@@ -305,10 +340,7 @@ Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags,
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
-
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted)
replaceSymbol<UndefinedData>(S, Name, Flags, File);
@@ -326,10 +358,7 @@ Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags,
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
-
- if (!File || File->kind() == InputFile::ObjectKind)
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(Name, File);
if (WasInserted)
replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type);
@@ -346,7 +375,7 @@ void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) {
Symbol *S;
bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
+ std::tie(S, WasInserted) = insert(Name, nullptr);
if (WasInserted) {
replaceSymbol<LazySymbol>(S, Name, File, *Sym);
diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h
index 26242e6cddd6..5e38e30692ab 100644
--- a/wasm/SymbolTable.h
+++ b/wasm/SymbolTable.h
@@ -13,12 +13,9 @@
#include "InputFiles.h"
#include "LTO.h"
#include "Symbols.h"
+#include "lld/Common/LLVM.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/Support/raw_ostream.h"
-
-using llvm::wasm::WasmGlobalType;
-using llvm::wasm::WasmSignature;
namespace lld {
namespace wasm {
@@ -59,6 +56,8 @@ public:
uint32_t Size);
Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
InputGlobal *G);
+ Symbol *addDefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
+ InputEvent *E);
Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File,
const WasmSignature *Signature);
@@ -66,7 +65,7 @@ public:
Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
const WasmGlobalType *Type);
- void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
+ void addLazy(ArchiveFile *F, const llvm::object::Archive::Symbol *Sym);
bool addComdat(StringRef Name);
@@ -77,7 +76,7 @@ public:
InputFunction *Function);
private:
- std::pair<Symbol *, bool> insert(StringRef Name);
+ std::pair<Symbol *, bool> insert(StringRef Name, InputFile *File);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap;
std::vector<Symbol *> SymVector;
diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp
index a11081cbcf77..4bef9761ec25 100644
--- a/wasm/Symbols.cpp
+++ b/wasm/Symbols.cpp
@@ -10,6 +10,7 @@
#include "Symbols.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputEvent.h"
#include "InputFiles.h"
#include "InputGlobal.h"
#include "OutputSegment.h"
@@ -27,7 +28,9 @@ DefinedFunction *WasmSym::CallCtors;
DefinedData *WasmSym::DsoHandle;
DefinedData *WasmSym::DataEnd;
DefinedData *WasmSym::HeapBase;
-DefinedGlobal *WasmSym::StackPointer;
+GlobalSymbol *WasmSym::StackPointer;
+UndefinedGlobal *WasmSym::TableBase;
+UndefinedGlobal *WasmSym::MemoryBase;
WasmSymbolType Symbol::getWasmType() const {
if (isa<FunctionSymbol>(this))
@@ -36,6 +39,8 @@ WasmSymbolType Symbol::getWasmType() const {
return WASM_SYMBOL_TYPE_DATA;
if (isa<GlobalSymbol>(this))
return WASM_SYMBOL_TYPE_GLOBAL;
+ if (isa<EventSymbol>(this))
+ return WASM_SYMBOL_TYPE_EVENT;
if (isa<SectionSymbol>(this))
return WASM_SYMBOL_TYPE_SECTION;
llvm_unreachable("invalid symbol kind");
@@ -52,6 +57,8 @@ InputChunk *Symbol::getChunk() const {
bool Symbol::isLive() const {
if (auto *G = dyn_cast<DefinedGlobal>(this))
return G->Global->Live;
+ if (auto *E = dyn_cast<DefinedEvent>(this))
+ return E->Event->Live;
if (InputChunk *C = getChunk())
return C->Live;
return Referenced;
@@ -60,6 +67,8 @@ bool Symbol::isLive() const {
void Symbol::markLive() {
if (auto *G = dyn_cast<DefinedGlobal>(this))
G->Global->Live = true;
+ if (auto *E = dyn_cast<DefinedEvent>(this))
+ E->Event->Live = true;
if (InputChunk *C = getChunk())
C->Live = true;
Referenced = true;
@@ -105,7 +114,10 @@ bool Symbol::isExported() const {
if (ForceExport || Config->ExportAll)
return true;
- return !isHidden();
+ if (Config->ExportDynamic && !isHidden())
+ return true;
+
+ return false;
}
uint32_t FunctionSymbol::getFunctionIndex() const {
@@ -207,6 +219,32 @@ DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File,
Global ? &Global->getType() : nullptr),
Global(Global) {}
+uint32_t EventSymbol::getEventIndex() const {
+ if (auto *F = dyn_cast<DefinedEvent>(this))
+ return F->Event->getEventIndex();
+ assert(EventIndex != INVALID_INDEX);
+ return EventIndex;
+}
+
+void EventSymbol::setEventIndex(uint32_t Index) {
+ LLVM_DEBUG(dbgs() << "setEventIndex " << Name << " -> " << Index << "\n");
+ assert(EventIndex == INVALID_INDEX);
+ EventIndex = Index;
+}
+
+bool EventSymbol::hasEventIndex() const {
+ if (auto *F = dyn_cast<DefinedEvent>(this))
+ return F->Event->hasEventIndex();
+ return EventIndex != INVALID_INDEX;
+}
+
+DefinedEvent::DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
+ InputEvent *Event)
+ : EventSymbol(Name, DefinedEventKind, Flags, File,
+ Event ? &Event->getType() : nullptr,
+ Event ? &Event->Signature : nullptr),
+ Event(Event) {}
+
uint32_t SectionSymbol::getOutputSectionIndex() const {
LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n");
assert(OutputSectionIndex != INVALID_INDEX);
@@ -223,10 +261,14 @@ void SectionSymbol::setOutputSectionIndex(uint32_t Index) {
void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); }
std::string lld::toString(const wasm::Symbol &Sym) {
+ return lld::maybeDemangleSymbol(Sym.getName());
+}
+
+std::string lld::maybeDemangleSymbol(StringRef Name) {
if (Config->Demangle)
- if (Optional<std::string> S = demangleItanium(Sym.getName()))
+ if (Optional<std::string> S = demangleItanium(Name))
return *S;
- return Sym.getName();
+ return Name;
}
std::string lld::toString(wasm::Symbol::Kind Kind) {
@@ -237,6 +279,8 @@ std::string lld::toString(wasm::Symbol::Kind Kind) {
return "DefinedData";
case wasm::Symbol::DefinedGlobalKind:
return "DefinedGlobal";
+ case wasm::Symbol::DefinedEventKind:
+ return "DefinedEvent";
case wasm::Symbol::UndefinedFunctionKind:
return "UndefinedFunction";
case wasm::Symbol::UndefinedDataKind:
diff --git a/wasm/Symbols.h b/wasm/Symbols.h
index 815cc97d22d1..11ee66550cdc 100644
--- a/wasm/Symbols.h
+++ b/wasm/Symbols.h
@@ -15,21 +15,17 @@
#include "llvm/Object/Archive.h"
#include "llvm/Object/Wasm.h"
-using llvm::object::Archive;
-using llvm::object::WasmSymbol;
-using llvm::wasm::WasmGlobal;
-using llvm::wasm::WasmGlobalType;
-using llvm::wasm::WasmSignature;
-using llvm::wasm::WasmSymbolType;
-
namespace lld {
namespace wasm {
+using llvm::wasm::WasmSymbolType;
+
class InputFile;
class InputChunk;
class InputSegment;
class InputFunction;
class InputGlobal;
+class InputEvent;
class InputSection;
#define INVALID_INDEX UINT32_MAX
@@ -41,6 +37,7 @@ public:
DefinedFunctionKind,
DefinedDataKind,
DefinedGlobalKind,
+ DefinedEventKind,
SectionKind,
UndefinedFunctionKind,
UndefinedDataKind,
@@ -52,7 +49,8 @@ public:
bool isDefined() const {
return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind ||
- SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind;
+ SymbolKind == DefinedGlobalKind || SymbolKind == DefinedEventKind ||
+ SymbolKind == SectionKind;
}
bool isUndefined() const {
@@ -126,12 +124,12 @@ public:
void setFunctionIndex(uint32_t Index);
bool hasFunctionIndex() const;
- const WasmSignature *FunctionType;
+ const WasmSignature *Signature;
protected:
FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
- const WasmSignature *Type)
- : Symbol(Name, K, Flags, F), FunctionType(Type) {}
+ const WasmSignature *Sig)
+ : Symbol(Name, K, Flags, F), Signature(Sig) {}
uint32_t TableIndex = INVALID_INDEX;
uint32_t FunctionIndex = INVALID_INDEX;
@@ -245,8 +243,6 @@ protected:
const WasmGlobalType *GlobalType)
: Symbol(Name, K, Flags, F), GlobalType(GlobalType) {}
- // 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;
};
@@ -274,16 +270,61 @@ public:
}
};
+// Wasm events are features that suspend the current execution and transfer the
+// control flow to a corresponding handler. Currently the only supported event
+// kind is exceptions.
+//
+// Event tags are values to distinguish different events. For exceptions, they
+// can be used to distinguish different language's exceptions, i.e., all C++
+// exceptions have the same tag. Wasm can generate code capable of doing
+// different handling actions based on the tag of caught exceptions.
+//
+// A single EventSymbol object represents a single tag. C++ exception event
+// symbol is a weak symbol generated in every object file in which exceptions
+// are used, and has name '__cpp_exception' for linking.
+class EventSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
+
+ const WasmEventType *getEventType() const { return EventType; }
+
+ // Get/set the event index
+ uint32_t getEventIndex() const;
+ void setEventIndex(uint32_t Index);
+ bool hasEventIndex() const;
+
+ const WasmSignature *Signature;
+
+protected:
+ EventSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
+ const WasmEventType *EventType, const WasmSignature *Sig)
+ : Symbol(Name, K, Flags, F), Signature(Sig), EventType(EventType) {}
+
+ const WasmEventType *EventType;
+ uint32_t EventIndex = INVALID_INDEX;
+};
+
+class DefinedEvent : public EventSymbol {
+public:
+ DefinedEvent(StringRef Name, uint32_t Flags, InputFile *File,
+ InputEvent *Event);
+
+ static bool classof(const Symbol *S) { return S->kind() == DefinedEventKind; }
+
+ InputEvent *Event;
+};
+
class LazySymbol : public Symbol {
public:
- LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym)
+ LazySymbol(StringRef Name, InputFile *File,
+ const llvm::object::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;
+ llvm::object::Archive::Symbol ArchiveSymbol;
};
// linker-generated symbols
@@ -291,7 +332,7 @@ struct WasmSym {
// __stack_pointer
// Global that holds the address of the top of the explicit value stack in
// linear memory.
- static DefinedGlobal *StackPointer;
+ static GlobalSymbol *StackPointer;
// __data_end
// Symbol marking the end of the data and bss.
@@ -310,6 +351,14 @@ struct WasmSym {
// __dso_handle
// Symbol used in calls to __cxa_atexit to determine current DLL
static DefinedData *DsoHandle;
+
+ // __table_base
+ // Used in PIC code for offset of indirect function table
+ static UndefinedGlobal *TableBase;
+
+ // __memory_base
+ // Used in PIC code for offset of global data
+ static UndefinedGlobal *MemoryBase;
};
// A buffer class that is large enough to hold any Symbol-derived
@@ -319,10 +368,11 @@ 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(DefinedEvent) char D[sizeof(DefinedEvent)];
+ alignas(LazySymbol) char E[sizeof(LazySymbol)];
+ alignas(UndefinedFunction) char F[sizeof(UndefinedFunction)];
+ alignas(UndefinedData) char G[sizeof(UndefinedData)];
+ alignas(UndefinedGlobal) char H[sizeof(UndefinedGlobal)];
alignas(SectionSymbol) char I[sizeof(SectionSymbol)];
};
@@ -330,7 +380,7 @@ 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(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
@@ -349,6 +399,7 @@ T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
// Returns a symbol name for an error message.
std::string toString(const wasm::Symbol &Sym);
std::string toString(wasm::Symbol::Kind Kind);
+std::string maybeDemangleSymbol(StringRef Name);
} // namespace lld
diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp
index 37ad32452a91..819d4298fef2 100644
--- a/wasm/Writer.cpp
+++ b/wasm/Writer.cpp
@@ -10,6 +10,7 @@
#include "Writer.h"
#include "Config.h"
#include "InputChunks.h"
+#include "InputEvent.h"
#include "InputGlobal.h"
#include "OutputSections.h"
#include "OutputSegment.h"
@@ -39,7 +40,6 @@ 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 {
@@ -81,6 +81,7 @@ private:
void createFunctionSection();
void createTableSection();
void createGlobalSection();
+ void createEventSection();
void createExportSection();
void createImportSection();
void createMemorySection();
@@ -90,6 +91,7 @@ private:
void createCustomSections();
// Custom sections
+ void createDylinkSection();
void createRelocSections();
void createLinkingSection();
void createNameSection();
@@ -98,18 +100,25 @@ private:
void writeSections();
uint64_t FileSize = 0;
+ uint32_t TableBase = 0;
uint32_t NumMemoryPages = 0;
uint32_t MaxMemoryPages = 0;
+ // Memory size and aligment. Written to the "dylink" section
+ // when build with -shared or -pie.
+ uint32_t MemAlign = 0;
+ uint32_t MemSize = 0;
std::vector<const WasmSignature *> Types;
DenseMap<WasmSignature, int32_t> TypeIndices;
std::vector<const Symbol *> ImportedSymbols;
unsigned NumImportedFunctions = 0;
unsigned NumImportedGlobals = 0;
+ unsigned NumImportedEvents = 0;
std::vector<WasmExport> Exports;
std::vector<const DefinedData *> DefinedFakeGlobals;
std::vector<InputGlobal *> InputGlobals;
std::vector<InputFunction *> InputFunctions;
+ std::vector<InputEvent *> InputEvents;
std::vector<const FunctionSymbol *> IndirectFunctions;
std::vector<const Symbol *> SymtabEntries;
std::vector<WasmInitEntry> InitFunctions;
@@ -155,17 +164,19 @@ void Writer::createImportSection() {
Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX;
Import.Memory.Maximum = MaxMemoryPages;
}
+ if (Config->SharedMemory)
+ Import.Memory.Flags |= WASM_LIMITS_FLAG_IS_SHARED;
writeImport(OS, Import);
}
if (Config->ImportTable) {
- uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
+ uint32_t TableSize = TableBase + 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};
+ Import.Table.ElemType = WASM_TYPE_FUNCREF;
+ Import.Table.Limits = {0, TableSize, 0};
writeImport(OS, Import);
}
@@ -175,11 +186,15 @@ void Writer::createImportSection() {
Import.Field = Sym->getName();
if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
Import.Kind = WASM_EXTERNAL_FUNCTION;
- Import.SigIndex = lookupType(*FunctionSym->FunctionType);
- } else {
- auto *GlobalSym = cast<GlobalSymbol>(Sym);
+ Import.SigIndex = lookupType(*FunctionSym->Signature);
+ } else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
Import.Kind = WASM_EXTERNAL_GLOBAL;
Import.Global = *GlobalSym->getGlobalType();
+ } else {
+ auto *EventSym = cast<EventSymbol>(Sym);
+ Import.Kind = WASM_EXTERNAL_EVENT;
+ Import.Event.Attribute = EventSym->getEventType()->Attribute;
+ Import.Event.SigIndex = lookupType(*EventSym->Signature);
}
writeImport(OS, Import);
}
@@ -214,8 +229,12 @@ void Writer::createMemorySection() {
bool HasMax = MaxMemoryPages != 0;
writeUleb128(OS, 1, "memory count");
- writeUleb128(OS, HasMax ? static_cast<unsigned>(WASM_LIMITS_FLAG_HAS_MAX) : 0,
- "memory limits flags");
+ unsigned Flags = 0;
+ if (HasMax)
+ Flags |= WASM_LIMITS_FLAG_HAS_MAX;
+ if (Config->SharedMemory)
+ Flags |= WASM_LIMITS_FLAG_IS_SHARED;
+ writeUleb128(OS, Flags, "memory limits flags");
writeUleb128(OS, NumMemoryPages, "initial pages");
if (HasMax)
writeUleb128(OS, MaxMemoryPages, "max pages");
@@ -241,6 +260,31 @@ void Writer::createGlobalSection() {
}
}
+// The event section contains a list of declared wasm events associated with the
+// module. Currently the only supported event kind is exceptions. A single event
+// entry represents a single event with an event tag. All C++ exceptions are
+// represented by a single event. An event entry in this section contains
+// information on what kind of event it is (e.g. exception) and the type of
+// values contained in a single event object. (In wasm, an event can contain
+// multiple values of primitive types. But for C++ exceptions, we just throw a
+// pointer which is an i32 value (for wasm32 architecture), so the signature of
+// C++ exception is (i32)->(void), because all event types are assumed to have
+// void return type to share WasmSignature with functions.)
+void Writer::createEventSection() {
+ unsigned NumEvents = InputEvents.size();
+ if (NumEvents == 0)
+ return;
+
+ SyntheticSection *Section = createSyntheticSection(WASM_SEC_EVENT);
+ raw_ostream &OS = Section->getStream();
+
+ writeUleb128(OS, NumEvents, "event count");
+ for (InputEvent *E : InputEvents) {
+ E->Event.Type.SigIndex = lookupType(E->Signature);
+ writeEvent(OS, E->Event);
+ }
+}
+
void Writer::createTableSection() {
if (Config->ImportTable)
return;
@@ -253,14 +297,14 @@ void Writer::createTableSection() {
// 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 = kInitialTableOffset + IndirectFunctions.size();
+ uint32_t TableSize = TableBase + IndirectFunctions.size();
SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
raw_ostream &OS = Section->getStream();
writeUleb128(OS, 1, "table count");
WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
- writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits});
+ writeTableType(OS, WasmTable{WASM_TYPE_FUNCREF, Limits});
}
void Writer::createExportSection() {
@@ -319,12 +363,17 @@ void Writer::createElemSection() {
writeUleb128(OS, 1, "segment count");
writeUleb128(OS, 0, "table index");
WasmInitExpr InitExpr;
- InitExpr.Opcode = WASM_OPCODE_I32_CONST;
- InitExpr.Value.Int32 = kInitialTableOffset;
+ if (Config->Pic) {
+ InitExpr.Opcode = WASM_OPCODE_GLOBAL_GET;
+ InitExpr.Value.Global = WasmSym::TableBase->getGlobalIndex();
+ } else {
+ InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+ InitExpr.Value.Int32 = TableBase;
+ }
writeInitExpr(OS, InitExpr);
writeUleb128(OS, IndirectFunctions.size(), "elem count");
- uint32_t TableIndex = kInitialTableOffset;
+ uint32_t TableIndex = TableBase;
for (const FunctionSymbol *Sym : IndirectFunctions) {
assert(Sym->getTableIndex() == TableIndex);
writeUleb128(OS, Sym->getFunctionIndex(), "function index");
@@ -419,6 +468,21 @@ public:
raw_string_ostream OS{Body};
};
+// Create the custom "dylink" section containing information for the dynamic
+// linker.
+// See
+// https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+void Writer::createDylinkSection() {
+ SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "dylink");
+ raw_ostream &OS = Section->getStream();
+
+ writeUleb128(OS, MemSize, "MemSize");
+ writeUleb128(OS, MemAlign, "MemAlign");
+ writeUleb128(OS, IndirectFunctions.size(), "TableSize");
+ writeUleb128(OS, 0, "TableAlign");
+ writeUleb128(OS, 0, "Needed"); // TODO: Support "needed" shared libraries
+}
+
// Create the custom "linking" section containing linker metadata.
// This is only created when relocatable output is requested.
void Writer::createLinkingSection() {
@@ -448,6 +512,10 @@ void Writer::createLinkingSection() {
writeUleb128(Sub.OS, G->getGlobalIndex(), "index");
if (Sym->isDefined())
writeStr(Sub.OS, Sym->getName(), "sym name");
+ } else if (auto *E = dyn_cast<EventSymbol>(Sym)) {
+ writeUleb128(Sub.OS, E->getEventIndex(), "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)) {
@@ -548,8 +616,7 @@ void Writer::createNameSection() {
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");
+ writeStr(Sub.OS, toString(*S), "symbol name");
}
}
for (const InputFunction *F : InputFunctions) {
@@ -558,8 +625,7 @@ void Writer::createNameSection() {
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");
+ writeStr(Sub.OS, maybeDemangleSymbol(F->getName()), "symbol name");
}
}
}
@@ -586,16 +652,16 @@ void Writer::writeSections() {
// - 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.
+// 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;
auto PlaceStack = [&]() {
- if (Config->Relocatable)
+ if (Config->Relocatable || Config->Shared)
return;
MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
@@ -603,7 +669,8 @@ void Writer::layoutMemory() {
log("mem: stack size = " + Twine(Config->ZStackSize));
log("mem: stack base = " + Twine(MemoryPtr));
MemoryPtr += Config->ZStackSize;
- WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
+ auto *SP = cast<DefinedGlobal>(WasmSym::StackPointer);
+ SP->Global->Global.InitExpr.Value.Int32 = MemoryPtr;
log("mem: stack top = " + Twine(MemoryPtr));
};
@@ -621,8 +688,10 @@ void Writer::layoutMemory() {
if (WasmSym::DsoHandle)
WasmSym::DsoHandle->setVirtualAddress(DataStart);
+ MemAlign = 0;
for (OutputSegment *Seg : Segments) {
- MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
+ MemAlign = std::max(MemAlign, Seg->Alignment);
+ MemoryPtr = alignTo(MemoryPtr, 1 << Seg->Alignment);
Seg->StartVA = MemoryPtr;
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name,
MemoryPtr, Seg->Size, Seg->Alignment));
@@ -635,6 +704,11 @@ void Writer::layoutMemory() {
log("mem: static data = " + Twine(MemoryPtr - DataStart));
+ if (Config->Shared) {
+ MemSize = MemoryPtr;
+ return;
+ }
+
if (!Config->StackFirst)
PlaceStack();
@@ -654,8 +728,8 @@ void Writer::layoutMemory() {
else
MemoryPtr = Config->InitialMemory;
}
- uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize);
- NumMemoryPages = MemSize / WasmPageSize;
+ MemSize = MemoryPtr;
+ NumMemoryPages = alignTo(MemoryPtr, WasmPageSize) / WasmPageSize;
log("mem: total pages = " + Twine(NumMemoryPages));
if (Config->MaxMemory != 0) {
@@ -678,12 +752,15 @@ SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
void Writer::createSections() {
// Known sections
+ if (Config->Pic)
+ createDylinkSection();
createTypeSection();
createImportSection();
createFunctionSection();
createTableSection();
createMemorySection();
createGlobalSection();
+ createEventSection();
createExportSection();
createElemSection();
createCodeSection();
@@ -722,8 +799,10 @@ void Writer::calculateImports() {
ImportedSymbols.emplace_back(Sym);
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
F->setFunctionIndex(NumImportedFunctions++);
+ else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
+ G->setGlobalIndex(NumImportedGlobals++);
else
- cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++);
+ cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
}
}
@@ -759,6 +838,8 @@ void Writer::calculateExports() {
continue;
}
Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()};
+ } else if (auto *E = dyn_cast<DefinedEvent>(Sym)) {
+ Export = {Name, WASM_EXTERNAL_EVENT, E->getEventIndex()};
} else {
auto *D = cast<DefinedData>(Sym);
DefinedFakeGlobals.emplace_back(D);
@@ -836,6 +917,8 @@ void Writer::calculateTypes() {
// 1. Any signature used in the TYPE relocation
// 2. The signatures of all imported functions
// 3. The signatures of all defined functions
+ // 4. The signatures of all imported events
+ // 5. The signatures of all defined events
for (ObjFile *File : Symtab->ObjectFiles) {
ArrayRef<WasmSignature> Types = File->getWasmObj()->types();
@@ -844,16 +927,23 @@ void Writer::calculateTypes() {
File->TypeMap[I] = registerType(Types[I]);
}
- for (const Symbol *Sym : ImportedSymbols)
+ for (const Symbol *Sym : ImportedSymbols) {
if (auto *F = dyn_cast<FunctionSymbol>(Sym))
- registerType(*F->FunctionType);
+ registerType(*F->Signature);
+ else if (auto *E = dyn_cast<EventSymbol>(Sym))
+ registerType(*E->Signature);
+ }
for (const InputFunction *F : InputFunctions)
registerType(F->Signature);
+
+ for (const InputEvent *E : InputEvents)
+ registerType(E->Signature);
}
void Writer::assignIndexes() {
- uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size();
+ assert(InputFunctions.empty());
+ uint32_t FunctionIndex = NumImportedFunctions;
auto AddDefinedFunction = [&](InputFunction *Func) {
if (!Func->Live)
return;
@@ -870,7 +960,7 @@ void Writer::assignIndexes() {
AddDefinedFunction(Func);
}
- uint32_t TableIndex = kInitialTableOffset;
+ uint32_t TableIndex = TableBase;
auto HandleRelocs = [&](InputChunk *Chunk) {
if (!Chunk->Live)
return;
@@ -902,7 +992,8 @@ void Writer::assignIndexes() {
HandleRelocs(P);
}
- uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size();
+ assert(InputGlobals.empty());
+ uint32_t GlobalIndex = NumImportedGlobals;
auto AddDefinedGlobal = [&](InputGlobal *Global) {
if (Global->Live) {
LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n");
@@ -919,9 +1010,29 @@ void Writer::assignIndexes() {
for (InputGlobal *Global : File->Globals)
AddDefinedGlobal(Global);
}
+
+ assert(InputEvents.empty());
+ uint32_t EventIndex = NumImportedEvents;
+ auto AddDefinedEvent = [&](InputEvent *Event) {
+ if (Event->Live) {
+ LLVM_DEBUG(dbgs() << "AddDefinedEvent: " << EventIndex << "\n");
+ Event->setEventIndex(EventIndex++);
+ InputEvents.push_back(Event);
+ }
+ };
+
+ for (ObjFile *File : Symtab->ObjectFiles) {
+ LLVM_DEBUG(dbgs() << "Events: " << File->getName() << "\n");
+ for (InputEvent *Event : File->Events)
+ AddDefinedEvent(Event);
+ }
}
static StringRef getOutputDataSegmentName(StringRef Name) {
+ // With PIC code we currently only support a single data segment since
+ // we only have a single __memory_base to use as our base address.
+ if (Config->Pic)
+ return "data";
if (!Config->MergeDataSegments)
return Name;
if (Name.startswith(".text."))
@@ -930,6 +1041,8 @@ static StringRef getOutputDataSegmentName(StringRef Name) {
return ".data";
if (Name.startswith(".bss."))
return ".bss";
+ if (Name.startswith(".rodata."))
+ return ".rodata";
return Name;
}
@@ -977,7 +1090,7 @@ void Writer::createCtorFunction() {
OS << BodyContent;
}
- ArrayRef<uint8_t> Body = toArrayRef(Saver.save(FunctionBody));
+ ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body);
}
@@ -989,7 +1102,7 @@ void Writer::calculateInitFunctions() {
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})
+ if (*Sym->Signature != WasmSignature{{}, {}})
error("invalid signature for init func: " + toString(*Sym));
InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority});
}
@@ -1004,9 +1117,14 @@ void Writer::calculateInitFunctions() {
}
void Writer::run() {
- if (Config->Relocatable)
+ if (Config->Relocatable || Config->Pic)
Config->GlobalBase = 0;
+ // For PIC code the table base is assigned dynamically by the loader.
+ // For non-PIC, we start at 1 so that accessing table index 0 always traps.
+ if (!Config->Pic)
+ TableBase = 1;
+
log("-- calculateImports");
calculateImports();
log("-- assignIndexes");
@@ -1029,8 +1147,10 @@ void Writer::run() {
if (errorHandler().Verbose) {
log("Defined Functions: " + Twine(InputFunctions.size()));
log("Defined Globals : " + Twine(InputGlobals.size()));
+ log("Defined Events : " + Twine(InputEvents.size()));
log("Function Imports : " + Twine(NumImportedFunctions));
log("Global Imports : " + Twine(NumImportedGlobals));
+ log("Event Imports : " + Twine(NumImportedEvents));
for (ObjFile *File : Symtab->ObjectFiles)
File->dumpInfo();
}
diff --git a/wasm/WriterUtils.cpp b/wasm/WriterUtils.cpp
index 201529edeaa6..80bfc0916121 100644
--- a/wasm/WriterUtils.cpp
+++ b/wasm/WriterUtils.cpp
@@ -17,22 +17,6 @@
using namespace llvm;
using namespace llvm::wasm;
-using namespace lld::wasm;
-
-static const char *valueTypeToString(uint8_t Type) {
- switch (Type) {
- case WASM_TYPE_I32:
- return "i32";
- case WASM_TYPE_I64:
- return "i64";
- case WASM_TYPE_F32:
- return "f32";
- case WASM_TYPE_F64:
- return "f64";
- default:
- llvm_unreachable("invalid value type");
- }
-}
namespace lld {
@@ -73,21 +57,20 @@ void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
support::endian::write(OS, Number, support::little);
}
-void wasm::writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg) {
- writeU8(OS, Type, Msg + "[type: " + valueTypeToString(Type) + "]");
+void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) {
+ writeU8(OS, static_cast<uint8_t>(Type),
+ Msg + "[type: " + toString(Type) + "]");
}
void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
writeU8(OS, WASM_TYPE_FUNC, "signature type");
- writeUleb128(OS, Sig.ParamTypes.size(), "param Count");
- for (uint8_t ParamType : Sig.ParamTypes) {
+ writeUleb128(OS, Sig.Params.size(), "param Count");
+ for (ValType ParamType : Sig.Params) {
writeValueType(OS, ParamType, "param type");
}
- if (Sig.ReturnType == WASM_TYPE_NORESULT) {
- writeUleb128(OS, 0, "result Count");
- } else {
- writeUleb128(OS, 1, "result Count");
- writeValueType(OS, Sig.ReturnType, "result type");
+ writeUleb128(OS, Sig.Returns.size(), "result Count");
+ if (Sig.Returns.size()) {
+ writeValueType(OS, Sig.Returns[0], "result type");
}
}
@@ -100,7 +83,7 @@ void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
case WASM_OPCODE_I64_CONST:
writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
break;
- case WASM_OPCODE_GET_GLOBAL:
+ case WASM_OPCODE_GLOBAL_GET:
writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
break;
default:
@@ -117,7 +100,8 @@ void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
}
void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
- writeValueType(OS, Type.Type, "global type");
+ // TODO: Update WasmGlobalType to use ValType and remove this cast.
+ writeValueType(OS, ValType(Type.Type), "global type");
writeU8(OS, Type.Mutable, "global mutable");
}
@@ -126,8 +110,17 @@ void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
writeInitExpr(OS, Global.InitExpr);
}
+void wasm::writeEventType(raw_ostream &OS, const WasmEventType &Type) {
+ writeUleb128(OS, Type.Attribute, "event attribute");
+ writeUleb128(OS, Type.SigIndex, "sig index");
+}
+
+void wasm::writeEvent(raw_ostream &OS, const WasmEvent &Event) {
+ writeEventType(OS, Event.Type);
+}
+
void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
- writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
+ writeU8(OS, WASM_TYPE_FUNCREF, "table type");
writeLimits(OS, Type.Limits);
}
@@ -142,6 +135,9 @@ void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
case WASM_EXTERNAL_GLOBAL:
writeGlobalType(OS, Import.Global);
break;
+ case WASM_EXTERNAL_EVENT:
+ writeEventType(OS, Import.Event);
+ break;
case WASM_EXTERNAL_MEMORY:
writeLimits(OS, Import.Memory);
break;
@@ -178,13 +174,15 @@ void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
std::string lld::toString(ValType Type) {
switch (Type) {
case ValType::I32:
- return "I32";
+ return "i32";
case ValType::I64:
- return "I64";
+ return "i64";
case ValType::F32:
- return "F32";
+ return "f32";
case ValType::F64:
- return "F64";
+ return "f64";
+ case ValType::V128:
+ return "v128";
case ValType::EXCEPT_REF:
return "except_ref";
}
@@ -193,20 +191,26 @@ std::string lld::toString(ValType Type) {
std::string lld::toString(const WasmSignature &Sig) {
SmallString<128> S("(");
- for (uint32_t Type : Sig.ParamTypes) {
+ for (ValType Type : Sig.Params) {
if (S.size() != 1)
S += ", ";
- S += toString(static_cast<ValType>(Type));
+ S += toString(Type);
}
S += ") -> ";
- if (Sig.ReturnType == WASM_TYPE_NORESULT)
+ if (Sig.Returns.size() == 0)
S += "void";
else
- S += toString(static_cast<ValType>(Sig.ReturnType));
+ S += toString(Sig.Returns[0]);
return S.str();
}
-std::string lld::toString(const WasmGlobalType &Sig) {
- return (Sig.Mutable ? "var " : "const ") +
- toString(static_cast<ValType>(Sig.Type));
+std::string lld::toString(const WasmGlobalType &Type) {
+ return (Type.Mutable ? "var " : "const ") +
+ toString(static_cast<ValType>(Type.Type));
+}
+
+std::string lld::toString(const WasmEventType &Type) {
+ if (Type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
+ return "exception";
+ return "unknown";
}
diff --git a/wasm/WriterUtils.h b/wasm/WriterUtils.h
index 74d727b24b40..7fc4b5aa83dc 100644
--- a/wasm/WriterUtils.h
+++ b/wasm/WriterUtils.h
@@ -13,9 +13,6 @@
#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;
namespace lld {
namespace wasm {
@@ -35,7 +32,8 @@ void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg);
void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg);
-void writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg);
+void writeValueType(raw_ostream &OS, llvm::wasm::ValType Type,
+ const Twine &Msg);
void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig);
@@ -47,6 +45,10 @@ void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type);
void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
+void writeEventType(raw_ostream &OS, const llvm::wasm::WasmEventType &Type);
+
+void writeEvent(raw_ostream &OS, const llvm::wasm::WasmEvent &Event);
+
void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
@@ -57,7 +59,8 @@ void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
std::string toString(llvm::wasm::ValType Type);
std::string toString(const llvm::wasm::WasmSignature &Sig);
-std::string toString(const llvm::wasm::WasmGlobalType &Sig);
+std::string toString(const llvm::wasm::WasmGlobalType &Type);
+std::string toString(const llvm::wasm::WasmEventType &Type);
} // namespace lld