aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-04-16 16:03:39 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-04-16 16:03:39 +0000
commitd2d3ebb81992e107edf95c1c136d7a342d9b1418 (patch)
treebb1af8fff2b1400cf240e3b2532a1e5d22a121da
parent16787c9ce0b96aaa669d7fab3a495916b35ce758 (diff)
downloadsrc-d2d3ebb81992e107edf95c1c136d7a342d9b1418.tar.gz
src-d2d3ebb81992e107edf95c1c136d7a342d9b1418.zip
Vendor import of lld trunk r300422:vendor/lld/lld-trunk-r300422
Notes
Notes: svn path=/vendor/lld/dist/; revision=317025 svn path=/vendor/lld/lld-trunk-r300422/; revision=317026; tag=vendor/lld/lld-trunk-r300422
-rw-r--r--CMakeLists.txt68
-rw-r--r--COFF/CMakeLists.txt5
-rw-r--r--COFF/Chunks.cpp9
-rw-r--r--COFF/Chunks.h4
-rw-r--r--COFF/Config.h14
-rw-r--r--COFF/Driver.cpp287
-rw-r--r--COFF/Driver.h4
-rw-r--r--COFF/DriverUtils.cpp71
-rw-r--r--COFF/Error.cpp74
-rw-r--r--COFF/Error.h10
-rw-r--r--COFF/ICF.cpp9
-rw-r--r--COFF/InputFiles.cpp94
-rw-r--r--COFF/InputFiles.h11
-rw-r--r--COFF/LTO.cpp140
-rw-r--r--COFF/LTO.h56
-rw-r--r--COFF/Librarian.cpp13
-rw-r--r--COFF/MapFile.cpp114
-rw-r--r--COFF/MapFile.h22
-rw-r--r--COFF/ModuleDef.cpp22
-rw-r--r--COFF/Options.td8
-rw-r--r--COFF/PDB.cpp109
-rw-r--r--COFF/SymbolTable.cpp173
-rw-r--r--COFF/SymbolTable.h17
-rw-r--r--COFF/Symbols.cpp9
-rw-r--r--COFF/Symbols.h78
-rw-r--r--COFF/Writer.cpp61
-rw-r--r--COFF/Writer.h51
-rw-r--r--ELF/CMakeLists.txt5
-rw-r--r--ELF/Config.h90
-rw-r--r--ELF/Driver.cpp419
-rw-r--r--ELF/Driver.h2
-rw-r--r--ELF/DriverUtils.cpp28
-rw-r--r--ELF/EhFrame.cpp30
-rw-r--r--ELF/EhFrame.h5
-rw-r--r--ELF/Error.cpp48
-rw-r--r--ELF/Error.h15
-rw-r--r--ELF/Filesystem.cpp79
-rw-r--r--ELF/Filesystem.h22
-rw-r--r--ELF/GdbIndex.cpp208
-rw-r--r--ELF/GdbIndex.h51
-rw-r--r--ELF/ICF.cpp100
-rw-r--r--ELF/InputFiles.cpp373
-rw-r--r--ELF/InputFiles.h55
-rw-r--r--ELF/InputSection.cpp755
-rw-r--r--ELF/InputSection.h275
-rw-r--r--ELF/LTO.cpp63
-rw-r--r--ELF/LTO.h3
-rw-r--r--ELF/LinkerScript.cpp1919
-rw-r--r--ELF/LinkerScript.h217
-rw-r--r--ELF/MapFile.cpp131
-rw-r--r--ELF/MapFile.h22
-rw-r--r--ELF/MarkLive.cpp122
-rw-r--r--ELF/Options.td43
-rw-r--r--ELF/OutputSections.cpp626
-rw-r--r--ELF/OutputSections.h231
-rw-r--r--ELF/Relocations.cpp1036
-rw-r--r--ELF/Relocations.h58
-rw-r--r--ELF/ScriptLexer.cpp285
-rw-r--r--ELF/ScriptLexer.h56
-rw-r--r--ELF/ScriptParser.cpp1235
-rw-r--r--ELF/ScriptParser.h38
-rw-r--r--ELF/Strings.cpp4
-rw-r--r--ELF/SymbolTable.cpp147
-rw-r--r--ELF/SymbolTable.h33
-rw-r--r--ELF/Symbols.cpp260
-rw-r--r--ELF/Symbols.h212
-rw-r--r--ELF/SyntheticSections.cpp1613
-rw-r--r--ELF/SyntheticSections.h464
-rw-r--r--ELF/Target.cpp437
-rw-r--r--ELF/Target.h24
-rw-r--r--ELF/Threads.h9
-rw-r--r--ELF/Thunks.cpp208
-rw-r--r--ELF/Thunks.h39
-rw-r--r--ELF/Writer.cpp1194
-rw-r--r--ELF/Writer.h20
-rw-r--r--docs/AtomLLD.rst5
-rw-r--r--docs/C++11.rst9
-rw-r--r--docs/Driver.rst3
-rw-r--r--docs/NewLLD.rst46
-rw-r--r--docs/Readers.rst3
-rw-r--r--docs/ReleaseNotes.rst96
-rw-r--r--docs/conf.py6
-rw-r--r--docs/design.rst3
-rw-r--r--docs/development.rst9
-rw-r--r--docs/index.rst184
-rw-r--r--include/lld/Core/Parallel.h3
-rw-r--r--include/lld/Core/TargetOptionsCommandFlags.h20
-rw-r--r--include/lld/Driver/Driver.h3
-rw-r--r--lib/Core/CMakeLists.txt9
-rw-r--r--lib/Core/TargetOptionsCommandFlags.cpp32
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_arm64.cpp4
-rw-r--r--lib/ReaderWriter/MachO/ArchHandler_x86.cpp9
-rw-r--r--lib/ReaderWriter/MachO/CMakeLists.txt2
-rw-r--r--test/CMakeLists.txt35
-rw-r--r--test/COFF/Inputs/bar.ll6
-rw-r--r--test/COFF/Inputs/msvclto.s3
-rw-r--r--test/COFF/Inputs/thinlto-mangled-qux.ll28
-rw-r--r--test/COFF/def-name.test28
-rw-r--r--test/COFF/driver-windows.test3
-rw-r--r--test/COFF/error-limit.test29
-rw-r--r--test/COFF/export32.test10
-rw-r--r--test/COFF/hello32.test5
-rw-r--r--test/COFF/include-lto.ll24
-rw-r--r--test/COFF/invalid-debug-type.test5
-rw-r--r--test/COFF/lldmap.test9
-rw-r--r--test/COFF/lto-comdat.ll69
-rw-r--r--test/COFF/lto-debug-pass-arguments.ll16
-rw-r--r--test/COFF/lto-parallel.ll8
-rw-r--r--test/COFF/msvclto-archive.ll39
-rw-r--r--test/COFF/msvclto.ll18
-rw-r--r--test/COFF/nopdb.test14
-rw-r--r--test/COFF/pdb-none.test13
-rw-r--r--test/COFF/pdb.test222
-rw-r--r--test/COFF/rsds.test25
-rw-r--r--test/COFF/savetemps.ll28
-rw-r--r--test/COFF/thinlto-archives.ll22
-rw-r--r--test/COFF/thinlto-mangled.ll16
-rw-r--r--test/COFF/thinlto.ll18
-rw-r--r--test/COFF/weak-external.test5
-rw-r--r--test/COFF/weak-external3.test10
-rw-r--r--test/ELF/Inputs/i386-got32x-baseless.elfbin0 -> 628 bytes
-rw-r--r--test/ELF/Inputs/i386-reloc-16-error.s3
-rw-r--r--test/ELF/Inputs/i386-reloc-16.s3
-rw-r--r--test/ELF/Inputs/i386-reloc-8-error.s3
-rw-r--r--test/ELF/Inputs/i386-reloc-8.s3
-rw-r--r--test/ELF/Inputs/icf-absolute.s3
-rw-r--r--test/ELF/Inputs/map-file2.s8
-rw-r--r--test/ELF/Inputs/map-file3.s2
-rw-r--r--test/ELF/Inputs/map-file4.s3
-rw-r--r--test/ELF/Inputs/relocatable-non-alloc.s6
-rw-r--r--test/ELF/Inputs/relocation-copy-align-common.s7
-rw-r--r--test/ELF/Inputs/resolution-end.s1
-rw-r--r--test/ELF/Inputs/x86-64-reloc-16-error.s3
-rw-r--r--test/ELF/Inputs/x86-64-reloc-16.s3
-rw-r--r--test/ELF/Inputs/x86-64-reloc-8-error.s3
-rw-r--r--test/ELF/Inputs/x86-64-reloc-8.s3
-rw-r--r--test/ELF/Inputs/ztext-text-notext.s10
-rw-r--r--test/ELF/aarch64-fpic-abs16.s4
-rw-r--r--test/ELF/aarch64-fpic-add_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-adr_prel_lo21.s4
-rw-r--r--test/ELF/aarch64-fpic-adr_prel_pg_hi21.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s4
-rw-r--r--test/ELF/aarch64-fpic-prel16.s4
-rw-r--r--test/ELF/aarch64-fpic-prel32.s4
-rw-r--r--test/ELF/aarch64-fpic-prel64.s4
-rw-r--r--test/ELF/abs-conflict.s4
-rw-r--r--test/ELF/arm-gnu-ifunc-plt.s28
-rw-r--r--test/ELF/arm-gnu-ifunc.s25
-rw-r--r--test/ELF/arm-icf-exidx.s31
-rw-r--r--test/ELF/arm-plt-reloc.s46
-rw-r--r--test/ELF/arm-target1.s8
-rw-r--r--test/ELF/arm-thumb-interwork-shared.s22
-rw-r--r--test/ELF/arm-thumb-interwork-thunk.s185
-rw-r--r--test/ELF/arm-thumb-plt-reloc.s17
-rw-r--r--test/ELF/arm-tls-gd-nonpreemptible.s72
-rw-r--r--test/ELF/as-needed-no-reloc.s2
-rw-r--r--test/ELF/basic-aarch64.s2
-rw-r--r--test/ELF/basic-mips.s2
-rw-r--r--test/ELF/basic-ppc.s2
-rw-r--r--test/ELF/basic.s7
-rw-r--r--test/ELF/basic32.s2
-rw-r--r--test/ELF/basic64be.s2
-rw-r--r--test/ELF/bss-start-common.s15
-rw-r--r--test/ELF/build-id.s6
-rw-r--r--test/ELF/compatible-section-types.s20
-rw-r--r--test/ELF/compressed-debug-input.s2
-rw-r--r--test/ELF/conflict.s32
-rw-r--r--test/ELF/copy-errors.s10
-rw-r--r--test/ELF/copy-in-shared.s5
-rw-r--r--test/ELF/copy-rel-pie-error.s9
-rw-r--r--test/ELF/default-fill.s38
-rw-r--r--test/ELF/driver.test9
-rw-r--r--test/ELF/dt_flags.s6
-rw-r--r--test/ELF/dynamic-list.s63
-rw-r--r--test/ELF/dynamic-reloc-in-ro.s6
-rw-r--r--test/ELF/early-exit-for-bad-paths.s35
-rw-r--r--test/ELF/edata-etext.s6
-rw-r--r--test/ELF/eh-frame-dyn-rel.s12
-rw-r--r--test/ELF/ehdr_start.s22
-rw-r--r--test/ELF/emit-relocs-merge.s20
-rw-r--r--test/ELF/emit-relocs-shared.s16
-rw-r--r--test/ELF/emit-relocs.s99
-rw-r--r--test/ELF/emulation.s6
-rw-r--r--test/ELF/end-abs.s11
-rw-r--r--test/ELF/gc-debuginfo-tls.s18
-rw-r--r--test/ELF/gc-merge-local-sym.s2
-rw-r--r--test/ELF/gc-sections-merge-addend.s2
-rw-r--r--test/ELF/gc-sections-merge-implicit-addend.s2
-rw-r--r--test/ELF/gc-sections-merge.s4
-rw-r--r--test/ELF/gc-sections-metadata-startstop.s33
-rw-r--r--test/ELF/gc-sections-metadata.s38
-rw-r--r--test/ELF/gc-sections-metadata2.s19
-rw-r--r--test/ELF/gnu-hash-table.s2
-rw-r--r--test/ELF/gnustack.s40
-rw-r--r--test/ELF/got32-i386.s23
-rw-r--r--test/ELF/got32x-i386.s47
-rw-r--r--test/ELF/hidden-vis-shared.s18
-rw-r--r--test/ELF/i386-pc16.test6
-rw-r--r--test/ELF/i386-pc8-pc16-addend.s17
-rw-r--r--test/ELF/i386-pc8.s15
-rw-r--r--test/ELF/i386-reloc-16.s14
-rw-r--r--test/ELF/i386-reloc-8.s14
-rw-r--r--test/ELF/i386-reloc8-reloc16-addend.s17
-rw-r--r--test/ELF/icf-absolute.s20
-rw-r--r--test/ELF/icf8.s14
-rw-r--r--test/ELF/icf9.s20
-rw-r--r--test/ELF/incompatible-section-types.s10
-rw-r--r--test/ELF/init-fini-progbits.s19
-rw-r--r--test/ELF/invalid-cie-length.s7
-rw-r--r--test/ELF/invalid-cie-length2.s7
-rw-r--r--test/ELF/invalid-cie-length3.s8
-rw-r--r--test/ELF/invalid-cie-length4.s9
-rw-r--r--test/ELF/invalid-fde-rel.s8
-rw-r--r--test/ELF/invalid-linkerscript.test2
-rw-r--r--test/ELF/invalid/broken-relaxation-x64.test (renamed from test/ELF/invalid/broken-relaxation-x64.s)0
-rw-r--r--test/ELF/invalid/dynamic-section-size.s2
-rw-r--r--test/ELF/invalid/invalid-relocation-x64.test (renamed from test/ELF/invalid/invalid-relocation-x64.s)4
-rw-r--r--test/ELF/invalid/mips-invalid-options-descriptor.s2
-rw-r--r--test/ELF/libsearch.s3
-rw-r--r--test/ELF/linkerscript/Inputs/lazy-symbols.s2
-rw-r--r--test/ELF/linkerscript/absolute.s17
-rw-r--r--test/ELF/linkerscript/addr-zero.s18
-rw-r--r--test/ELF/linkerscript/align.s87
-rw-r--r--test/ELF/linkerscript/alternate-sections.s40
-rw-r--r--test/ELF/linkerscript/assert.s4
-rw-r--r--test/ELF/linkerscript/at-addr.s39
-rw-r--r--test/ELF/linkerscript/at.s37
-rw-r--r--test/ELF/linkerscript/constructor.s13
-rw-r--r--test/ELF/linkerscript/discard-print-gc.s19
-rw-r--r--test/ELF/linkerscript/discard-section-metadata.s32
-rw-r--r--test/ELF/linkerscript/edata-etext.s9
-rw-r--r--test/ELF/linkerscript/eh-frame-reloc-out-of-range.s27
-rw-r--r--test/ELF/linkerscript/eh-frame.s19
-rw-r--r--test/ELF/linkerscript/ehdr_start.s3
-rw-r--r--test/ELF/linkerscript/emit-reloc.s17
-rw-r--r--test/ELF/linkerscript/emit-relocs-discard.s14
-rw-r--r--test/ELF/linkerscript/emit-relocs-ehframe-discard.s11
-rw-r--r--test/ELF/linkerscript/empty-load.s3
-rw-r--r--test/ELF/linkerscript/excludefile.s9
-rw-r--r--test/ELF/linkerscript/expr-invalid-sec.s6
-rw-r--r--test/ELF/linkerscript/expr-sections.s22
-rw-r--r--test/ELF/linkerscript/fill-exec-sections.s40
-rw-r--r--test/ELF/linkerscript/fill.s5
-rw-r--r--test/ELF/linkerscript/huge-temporary-file.s12
-rw-r--r--test/ELF/linkerscript/lazy-symbols.s13
-rw-r--r--test/ELF/linkerscript/locationcounter.s189
-rw-r--r--test/ELF/linkerscript/locationcountererr.s6
-rw-r--r--test/ELF/linkerscript/locationcountererr2.s9
-rw-r--r--test/ELF/linkerscript/memory.s114
-rw-r--r--test/ELF/linkerscript/merge-sections-syms.s49
-rw-r--r--test/ELF/linkerscript/merge-sections.s50
-rw-r--r--test/ELF/linkerscript/no-space.s6
-rw-r--r--test/ELF/linkerscript/non-absolute.s30
-rw-r--r--test/ELF/linkerscript/non-absolute2.s12
-rw-r--r--test/ELF/linkerscript/non-alloc.s6
-rw-r--r--test/ELF/linkerscript/numbers.s26
-rw-r--r--test/ELF/linkerscript/obj-symbol-value.s19
-rw-r--r--test/ELF/linkerscript/operators.s93
-rw-r--r--test/ELF/linkerscript/orphan-first-cmd.s4
-rw-r--r--test/ELF/linkerscript/out-of-order.s10
-rw-r--r--test/ELF/linkerscript/output-too-large.s8
-rw-r--r--test/ELF/linkerscript/outputarch.s8
-rw-r--r--test/ELF/linkerscript/outsections-addr.s22
-rw-r--r--test/ELF/linkerscript/page-size.s4
-rw-r--r--test/ELF/linkerscript/pt_gnu_eh_frame.s13
-rw-r--r--test/ELF/linkerscript/section-align.s62
-rw-r--r--test/ELF/linkerscript/sections-gc.s19
-rw-r--r--test/ELF/linkerscript/sections-gc2.s31
-rw-r--r--test/ELF/linkerscript/sections-padding.s11
-rw-r--r--test/ELF/linkerscript/sections-sort.s5
-rw-r--r--test/ELF/linkerscript/sections.s24
-rw-r--r--test/ELF/linkerscript/symbol-assignexpr.s4
-rw-r--r--test/ELF/linkerscript/symbol-only.s2
-rw-r--r--test/ELF/linkerscript/symbol-reserved.s16
-rw-r--r--test/ELF/linkerscript/symbols-non-alloc.s16
-rw-r--r--test/ELF/lto/Inputs/cache.ll10
-rw-r--r--test/ELF/lto/archive-no-index.ll39
-rw-r--r--test/ELF/lto/cache.ll21
-rw-r--r--test/ELF/lto/codemodel.ll20
-rw-r--r--test/ELF/lto/combined-lto-object-name.ll4
-rw-r--r--test/ELF/lto/duplicated.ll6
-rw-r--r--test/ELF/lto/opt-remarks.ll68
-rw-r--r--test/ELF/lto/parallel-internalize.ll3
-rw-r--r--test/ELF/lto/parallel.ll3
-rw-r--r--test/ELF/lto/thinlto.ll13
-rw-r--r--test/ELF/map-file.s62
-rw-r--r--test/ELF/merge-reloc.s8
-rw-r--r--test/ELF/merge-string-align.s4
-rw-r--r--test/ELF/merge-string.s28
-rw-r--r--test/ELF/merge.s2
-rw-r--r--test/ELF/mips-elf-flags-err.s9
-rw-r--r--test/ELF/mips-elf-flags.s4
-rw-r--r--test/ELF/mips-got-string.s28
-rw-r--r--test/ELF/mips-got16-relocatable.s40
-rw-r--r--test/ELF/mips-gp-ext.s4
-rw-r--r--test/ELF/mips-gprel-sec.s37
-rw-r--r--test/ELF/mips-npic-call-pic-os.s138
-rw-r--r--test/ELF/mips-npic-call-pic.s169
-rw-r--r--test/ELF/mips-options.s2
-rw-r--r--test/ELF/mips-reginfo.s2
-rw-r--r--test/ELF/mips-sto-pic-flag.s4
-rw-r--r--test/ELF/mips-tls-64.s3
-rw-r--r--test/ELF/mips-tls-hilo.s3
-rw-r--r--test/ELF/mips-tls.s3
-rw-r--r--test/ELF/no-dynamic-linker.s12
-rw-r--r--test/ELF/no-merge.s22
-rw-r--r--test/ELF/no-soname.s31
-rw-r--r--test/ELF/note-contiguous.s24
-rw-r--r--test/ELF/note-loadaddr.c35
-rw-r--r--test/ELF/note-multiple.s43
-rw-r--r--test/ELF/plt-i686.s12
-rw-r--r--test/ELF/pre_init_fini_array_missing.s13
-rw-r--r--test/ELF/relocatable-bss.s2
-rw-r--r--test/ELF/relocatable-common.s12
-rw-r--r--test/ELF/relocatable-eh-frame-hdr.s11
-rw-r--r--test/ELF/relocatable-eh-frame.s19
-rw-r--r--test/ELF/relocatable-ehframe.s4
-rw-r--r--test/ELF/relocatable-non-alloc.s10
-rw-r--r--test/ELF/relocatable-section-symbol.s49
-rw-r--r--test/ELF/relocatable-symbol-name.s28
-rw-r--r--test/ELF/relocatable.s2
-rw-r--r--test/ELF/relocation-copy-align-common.s40
-rw-r--r--test/ELF/relocation-group.test43
-rw-r--r--test/ELF/relocation-nocopy.s19
-rw-r--r--test/ELF/relocation-none-aarch64.test24
-rw-r--r--test/ELF/relocation-relative-absolute.s4
-rw-r--r--test/ELF/relro-omagic.s2
-rw-r--r--test/ELF/reproduce.s8
-rw-r--r--test/ELF/resolution-end.s13
-rw-r--r--test/ELF/retain-symbols-file.s44
-rw-r--r--test/ELF/retain-und.s18
-rw-r--r--test/ELF/section-name.s4
-rw-r--r--test/ELF/splitstacks.s2
-rw-r--r--test/ELF/startstop-gccollect.s16
-rw-r--r--test/ELF/static-with-export-dynamic.s32
-rw-r--r--test/ELF/sysroot.s3
-rw-r--r--test/ELF/tls-mismatch.s5
-rw-r--r--test/ELF/tls-static.s3
-rw-r--r--test/ELF/trace-symbols.s2
-rw-r--r--test/ELF/ttext-tdata-tbss.s11
-rw-r--r--test/ELF/undef-shared.s9
-rw-r--r--test/ELF/undef-with-plt-addr.s3
-rw-r--r--test/ELF/undef.s36
-rw-r--r--test/ELF/unknown-reloc.s14
-rw-r--r--test/ELF/unresolved-symbols.s10
-rw-r--r--test/ELF/verneed-local.s3
-rw-r--r--test/ELF/version-script-copy-rel.s24
-rw-r--r--test/ELF/version-script-extern-exact.s18
-rw-r--r--test/ELF/version-script-extern-wildcards-anon.s12
-rw-r--r--test/ELF/version-script-glob.s27
-rw-r--r--test/ELF/version-script.s3
-rw-r--r--test/ELF/warn-unresolved-symbols-hidden.s14
-rw-r--r--test/ELF/warn-unresolved-symbols.s51
-rw-r--r--test/ELF/x86-64-dyn-rel-error.s2
-rw-r--r--test/ELF/x86-64-dyn-rel-error2.s6
-rw-r--r--test/ELF/x86-64-reloc-16.s14
-rw-r--r--test/ELF/x86-64-reloc-32-fpic.s5
-rw-r--r--test/ELF/x86-64-reloc-8.s14
-rw-r--r--test/ELF/x86-64-reloc-pc32-fpic.s5
-rw-r--r--test/ELF/zdefs.s3
-rw-r--r--test/ELF/zstack-size.s37
-rw-r--r--test/ELF/ztext-text-notext.s36
-rw-r--r--test/lit.cfg16
-rw-r--r--test/lit.site.cfg.in4
-rw-r--r--tools/lld/lld.cpp8
-rw-r--r--unittests/CoreTests/CMakeLists.txt2
-rw-r--r--unittests/CoreTests/ParallelTest.cpp15
369 files changed, 12732 insertions, 7875 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be424efbbd87..7fcb1a748ffc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,8 +11,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
endif()
- execute_process(COMMAND "${LLVM_CONFIG_PATH}" "--obj-root" "--includedir"
+ execute_process(COMMAND "${LLVM_CONFIG_PATH}"
+ "--obj-root"
+ "--includedir"
"--cmakedir"
+ "--src-root"
RESULT_VARIABLE HAD_ERROR
OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -25,9 +28,11 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
+ list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
+ set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
@@ -49,6 +54,67 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
include(AddLLVM)
include(TableGen)
include(HandleLLVMOptions)
+
+ if(LLVM_INCLUDE_TESTS)
+ set(Python_ADDITIONAL_VERSIONS 2.7)
+ include(FindPythonInterp)
+ if(NOT PYTHONINTERP_FOUND)
+ message(FATAL_ERROR
+"Unable to find Python interpreter, required for testing.
+
+Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
+ endif()
+
+ if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
+ message(FATAL_ERROR "Python 2.7 or newer is required")
+ endif()
+
+ # Check prebuilt llvm/utils.
+ if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
+ AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
+ set(LLVM_UTILS_PROVIDED ON)
+ endif()
+
+ if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ # Note: path not really used, except for checking if lit was found
+ set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
+ if(NOT LLVM_UTILS_PROVIDED)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
+ set(LLVM_UTILS_PROVIDED ON)
+ set(LLD_TEST_DEPS FileCheck not)
+ endif()
+ set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
+ if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
+ AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
+ AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
+ add_subdirectory(${UNITTEST_DIR} utils/unittest)
+ endif()
+ else()
+ # Seek installed Lit.
+ find_program(LLVM_LIT
+ NAMES llvm-lit lit.py lit
+ PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
+ DOC "Path to lit.py")
+ endif()
+
+ if(LLVM_LIT)
+ # Define the default arguments to use with 'lit', and an option for the user
+ # to override.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+
+ # On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
+ if(WIN32 AND NOT CYGWIN)
+ set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
+ endif()
+ else()
+ set(LLVM_INCLUDE_TESTS OFF)
+ endif()
+ endif()
endif()
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt
index 70a33b9fdd81..8f24e36c0eca 100644
--- a/COFF/CMakeLists.txt
+++ b/COFF/CMakeLists.txt
@@ -15,6 +15,8 @@ add_lld_library(lldCOFF
ICF.cpp
InputFiles.cpp
Librarian.cpp
+ LTO.cpp
+ MapFile.cpp
MarkLive.cpp
ModuleDef.cpp
PDB.cpp
@@ -25,6 +27,7 @@ add_lld_library(lldCOFF
LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ BitReader
Core
DebugInfoCodeView
DebugInfoMSF
@@ -40,7 +43,7 @@ add_lld_library(lldCOFF
LINK_LIBS
lldCore
- ${PTHREAD_LIB}
+ ${LLVM_PTHREAD_LIB}
DEPENDS
COFFOptionsTableGen
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp
index 7f0dfa92ec10..10eeedd88e55 100644
--- a/COFF/Chunks.cpp
+++ b/COFF/Chunks.cpp
@@ -11,6 +11,7 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/Debug.h"
@@ -61,7 +62,7 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@@ -76,7 +77,7 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break;
case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@@ -136,7 +137,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym,
case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break;
case IMAGE_REL_ARM_SECREL: add32(Off, Sym->getSecrel()); break;
default:
- fatal("unsupported relocation type");
+ fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
}
@@ -226,7 +227,7 @@ void SectionChunk::printDiscardedMessage() const {
// Removed by dead-stripping. If it's removed by ICF, ICF already
// printed out the name, so don't repeat that here.
if (Sym && this == Repl)
- outs() << "Discarded " << Sym->getName() << "\n";
+ message("Discarded " + Sym->getName());
}
StringRef SectionChunk::getDebugName() {
diff --git a/COFF/Chunks.h b/COFF/Chunks.h
index 59e36b84c9b0..44d7f31afc67 100644
--- a/COFF/Chunks.h
+++ b/COFF/Chunks.h
@@ -187,10 +187,10 @@ public:
const coff_section *Header;
-private:
- // A file this chunk was created from.
+ // The file that this chunk was created from.
ObjectFile *File;
+private:
StringRef SectionName;
std::vector<SectionChunk *> AssocChildren;
llvm::iterator_range<const coff_relocation *> Relocs;
diff --git a/COFF/Config.h b/COFF/Config.h
index 0fa3338aa28c..31534aeb3971 100644
--- a/COFF/Config.h
+++ b/COFF/Config.h
@@ -80,14 +80,16 @@ struct Configuration {
SymbolBody *Entry = nullptr;
bool NoEntry = false;
std::string OutputFile;
+ bool ColorDiagnostics;
bool DoGC = true;
bool DoICF = true;
+ uint64_t ErrorLimit = 20;
bool Relocatable = true;
bool Force = false;
bool Debug = false;
bool WriteSymtab = true;
unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
- StringRef PDBPath;
+ llvm::SmallString<128> PDBPath;
// Symbols in this set are considered as live by the garbage collector.
std::set<SymbolBody *> GCRoot;
@@ -103,6 +105,8 @@ struct Configuration {
std::map<std::string, int> DLLOrder;
SymbolBody *DelayLoadHelper = nullptr;
+ bool SaveTemps = false;
+
// Used for SafeSEH.
Symbol *SEHTable = nullptr;
Symbol *SEHCount = nullptr;
@@ -111,7 +115,9 @@ struct Configuration {
unsigned LTOOptLevel = 2;
// Used for /opt:lldltojobs=N
- unsigned LTOJobs = 1;
+ unsigned LTOJobs = 0;
+ // Used for /opt:lldltopartitions=N
+ unsigned LTOPartitions = 1;
// Used for /merge:from=to (e.g. /merge:.rdata=.text)
std::map<StringRef, StringRef> Merge;
@@ -135,6 +141,9 @@ struct Configuration {
// Used for /alternatename.
std::map<StringRef, StringRef> AlternateNames;
+ // Used for /lldmap.
+ std::string MapFile;
+
uint64_t ImageBase = -1;
uint64_t StackReserve = 1024 * 1024;
uint64_t StackCommit = 4096;
@@ -151,6 +160,7 @@ struct Configuration {
bool TerminalServerAware = true;
bool LargeAddressAware = false;
bool HighEntropyVA = false;
+ bool AppContainer = false;
// This is for debugging.
bool DebugPdb = false;
diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp
index 4dabd9ebcc6d..3e7f10bf8d11 100644
--- a/COFF/Driver.cpp
+++ b/COFF/Driver.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/LibDriver/LibDriver.h"
+#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
@@ -31,17 +32,11 @@
#include <algorithm>
#include <memory>
-#ifdef _MSC_VER
-// <future> depends on <eh.h> for __uncaught_exception.
-#include <eh.h>
-#endif
-
#include <future>
using namespace llvm;
using namespace llvm::COFF;
using llvm::sys::Process;
-using llvm::sys::fs::OpenFlags;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;
@@ -55,11 +50,16 @@ BumpPtrAllocator BAlloc;
StringSaver Saver{BAlloc};
std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
-bool link(ArrayRef<const char *> Args) {
+bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
+ ErrorCount = 0;
+ ErrorOS = &Diag;
+ Argv0 = Args[0];
Config = make<Configuration>();
+ Config->ColorDiagnostics =
+ (ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
Driver = make<LinkerDriver>();
Driver->link(Args);
- return true;
+ return !ErrorCount;
}
// Drop directory components and replace extension with ".exe" or ".dll".
@@ -121,10 +121,12 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB) {
return Symtab.addFile(make<ArchiveFile>(MBRef));
if (Magic == file_magic::bitcode)
return Symtab.addFile(make<BitcodeFile>(MBRef));
+
if (Magic == file_magic::coff_cl_gl_object)
- fatal(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
+ error(MBRef.getBufferIdentifier() + ": is not a native COFF file. "
"Recompile without /GL");
- Symtab.addFile(make<ObjectFile>(MBRef));
+ else
+ Symtab.addFile(make<ObjectFile>(MBRef));
}
void LinkerDriver::enqueuePath(StringRef Path) {
@@ -134,12 +136,10 @@ void LinkerDriver::enqueuePath(StringRef Path) {
enqueueTask([=]() {
auto MBOrErr = Future->get();
if (MBOrErr.second)
- fatal(MBOrErr.second, "could not open " + PathStr);
- Driver->addBuffer(std::move(MBOrErr.first));
+ error("could not open " + PathStr + ": " + MBOrErr.second.message());
+ else
+ Driver->addBuffer(std::move(MBOrErr.first));
});
-
- if (Config->OutputFile == "")
- Config->OutputFile = getOutputPath(Path);
}
void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
@@ -151,17 +151,18 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef MB, StringRef SymName,
}
InputFile *Obj;
- if (Magic == file_magic::coff_object)
+ if (Magic == file_magic::coff_object) {
Obj = make<ObjectFile>(MB);
- else if (Magic == file_magic::bitcode)
+ } else if (Magic == file_magic::bitcode) {
Obj = make<BitcodeFile>(MB);
- else
- fatal("unknown file type: " + MB.getBufferIdentifier());
+ } else {
+ error("unknown file type: " + MB.getBufferIdentifier());
+ return;
+ }
Obj->ParentName = ParentName;
Symtab.addFile(Obj);
- if (Config->Verbose)
- outs() << "Loaded " << toString(Obj) << " for " << SymName << "\n";
+ log("Loaded " + toString(Obj) + " for " + SymName);
}
void LinkerDriver::enqueueArchiveMember(const Archive::Child &C,
@@ -234,7 +235,7 @@ void LinkerDriver::parseDirectives(StringRef S) {
case OPT_throwingnew:
break;
default:
- fatal(Arg->getSpelling() + " is not allowed in .drectve");
+ error(Arg->getSpelling() + " is not allowed in .drectve");
}
}
}
@@ -402,7 +403,8 @@ static unsigned parseDebugType(StringRef Arg) {
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));
+ .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
+ .Default(0);
return DebugTypes;
}
@@ -418,6 +420,132 @@ static std::string getMapFile(const opt::InputArgList &Args) {
return (OutFile.substr(0, OutFile.rfind('.')) + ".map").str();
}
+std::vector<MemoryBufferRef> getArchiveMembers(Archive *File) {
+ std::vector<MemoryBufferRef> V;
+ Error Err = Error::success();
+ for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) {
+ Archive::Child C =
+ check(COrErr,
+ File->getFileName() + ": could not get the child of the archive");
+ MemoryBufferRef MBRef =
+ check(C.getMemoryBufferRef(),
+ File->getFileName() +
+ ": could not get the buffer for a child of the archive");
+ V.push_back(MBRef);
+ }
+ if (Err)
+ fatal(File->getFileName() +
+ ": Archive::children failed: " + toString(std::move(Err)));
+ return V;
+}
+
+// A helper function for filterBitcodeFiles.
+static bool needsRebuilding(MemoryBufferRef MB) {
+ // The MSVC linker doesn't support thin archives, so if it's a thin
+ // archive, we always need to rebuild it.
+ std::unique_ptr<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 (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path),
+ ".lib", S))
+ fatal(EC, "cannot create a temporary file");
+ std::string Temp = S.str();
+ TemporaryFiles.push_back(Temp);
+
+ std::pair<StringRef, std::error_code> Ret =
+ llvm::writeArchive(Temp, New, /*WriteSymtab=*/true, Archive::Kind::K_GNU,
+ /*Deterministics=*/true,
+ /*Thin=*/false);
+ if (Ret.second)
+ error("failed to create a new archive " + S.str() + ": " + Ret.first);
+ return Temp;
+}
+
+// Create response file contents and invoke the MSVC linker.
+void LinkerDriver::invokeMSVC(opt::InputArgList &Args) {
+ std::string Rsp = "/nologo ";
+ std::vector<std::string> Temps;
+
+ 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) + " ";
+ continue;
+ }
+ Rsp += quote(Arg->getValue()) + " ";
+ break;
+ }
+ default:
+ Rsp += toString(Arg) + " ";
+ }
+ }
+
+ std::vector<StringRef> ObjectFiles = Symtab.compileBitcodeFiles();
+ runMSVCLinker(Rsp, ObjectFiles);
+
+ for (StringRef Path : Temps)
+ sys::fs::remove(Path);
+}
+
void LinkerDriver::enqueueTask(std::function<void()> Task) {
TaskQueue.push_back(std::move(Task));
}
@@ -451,6 +579,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Parse command line options.
opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1));
+ // Parse and evaluate -mllvm options.
+ std::vector<const char *> V;
+ V.push_back("lld-link (LLVM option parsing)");
+ for (auto *Arg : Args.filtered(OPT_mllvm))
+ V.push_back(Arg->getValue());
+ cl::ParseCommandLineOptions(V.size(), V.data());
+
+ // Handle /errorlimit early, because error() depends on it.
+ if (auto *Arg = Args.getLastArg(OPT_errorlimit)) {
+ int N = 20;
+ StringRef S = Arg->getValue();
+ if (S.getAsInteger(10, N))
+ error(Arg->getSpelling() + " number expected, but got " + S);
+ Config->ErrorLimit = N;
+ }
+
// Handle /help
if (Args.hasArg(OPT_help)) {
printHelp(ArgsArr[0]);
@@ -467,12 +611,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (ErrOrWriter) {
Tar = std::move(*ErrOrWriter);
} else {
- errs() << "/linkrepro: failed to open " << Path << ": "
- << toString(ErrOrWriter.takeError()) << '\n';
+ error("/linkrepro: failed to open " + Path + ": " +
+ toString(ErrOrWriter.takeError()));
}
}
- if (Args.filtered_begin(OPT_INPUT) == Args.filtered_end())
+ if (!Args.hasArgNoClaim(OPT_INPUT))
fatal("no input files");
// Construct search path list.
@@ -508,9 +652,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /noentry
if (Args.hasArg(OPT_noentry)) {
- if (!Args.hasArg(OPT_dll))
- fatal("/noentry must be specified with /dll");
- Config->NoEntry = true;
+ if (Args.hasArg(OPT_dll))
+ Config->NoEntry = true;
+ else
+ error("/noentry must be specified with /dll");
}
// Handle /dll
@@ -521,12 +666,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Handle /fixed
if (Args.hasArg(OPT_fixed)) {
- if (Args.hasArg(OPT_dynamicbase))
- fatal("/fixed must not be specified with /dynamicbase");
- Config->Relocatable = false;
- Config->DynamicBase = false;
+ if (Args.hasArg(OPT_dynamicbase)) {
+ error("/fixed must not be specified with /dynamicbase");
+ } else {
+ Config->Relocatable = false;
+ Config->DynamicBase = false;
+ }
}
+ if (Args.hasArg(OPT_appcontainer))
+ Config->AppContainer = true;
+
// Handle /machine
if (auto *Arg = Args.getLastArg(OPT_machine))
Config->Machine = getMachineType(Arg->getValue());
@@ -596,20 +746,31 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
StringRef OptLevel = StringRef(S).substr(7);
if (OptLevel.getAsInteger(10, Config->LTOOptLevel) ||
Config->LTOOptLevel > 3)
- fatal("/opt:lldlto: invalid optimization level: " + OptLevel);
+ error("/opt:lldlto: invalid optimization level: " + OptLevel);
continue;
}
if (StringRef(S).startswith("lldltojobs=")) {
StringRef Jobs = StringRef(S).substr(11);
if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0)
- fatal("/opt:lldltojobs: invalid job count: " + Jobs);
+ error("/opt:lldltojobs: invalid job count: " + Jobs);
+ continue;
+ }
+ if (StringRef(S).startswith("lldltopartitions=")) {
+ StringRef N = StringRef(S).substr(17);
+ if (N.getAsInteger(10, Config->LTOPartitions) ||
+ Config->LTOPartitions == 0)
+ error("/opt:lldltopartitions: invalid partition count: " + N);
continue;
}
if (S != "ref" && S != "lbr" && S != "nolbr")
- fatal("/opt: unknown option: " + S);
+ error("/opt: unknown option: " + S);
}
}
+ // Handle /lldsavetemps
+ if (Args.hasArg(OPT_lldsavetemps))
+ Config->SaveTemps = true;
+
// Handle /failifmismatch
for (auto *Arg : Args.filtered(OPT_failifmismatch))
checkFailIfMismatch(Arg->getValue());
@@ -658,6 +819,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
Config->DumpPdb = Args.hasArg(OPT_dumppdb);
Config->DebugPdb = Args.hasArg(OPT_debugpdb);
+ Config->MapFile = getMapFile(Args);
+
+ if (ErrorCount)
+ return;
+
// Create a list of input files. Files can be given as arguments
// for /defaultlib option.
std::vector<MemoryBufferRef> MBs;
@@ -678,7 +844,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// 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) {
- errs() << "warning: /machine is not specified. x64 is assumed.\n";
+ warn("/machine is not specified. x64 is assumed");
Config->Machine = AMD64;
}
@@ -715,8 +881,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
if (S.empty())
fatal("entry point must be defined");
Config->Entry = addUndefined(S);
- if (Config->Verbose)
- outs() << "Entry name inferred: " << S << "\n";
+ log("Entry name inferred: " + S);
}
// Handle /export
@@ -749,6 +914,22 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
}
+ // Set default image name if neither /out or /def set it.
+ if (Config->OutputFile.empty()) {
+ Config->OutputFile =
+ getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue());
+ }
+
+ // Put the PDB next to the image if no /pdb flag was passed.
+ if (Config->Debug && Config->PDBPath.empty()) {
+ Config->PDBPath = Config->OutputFile;
+ sys::path::replace_extension(Config->PDBPath, ".pdb");
+ }
+
+ // Disable PDB generation if the user requested it.
+ if (Args.hasArg(OPT_nopdb))
+ Config->PDBPath = "";
+
// Set default image base if /base is not given.
if (Config->ImageBase == uint64_t(-1))
Config->ImageBase = getDefaultImageBase();
@@ -801,6 +982,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
addUndefined(mangle("_load_config_used"));
} while (run());
+ if (ErrorCount)
+ return;
+
+ // If /msvclto is given, we use the MSVC linker to link LTO output files.
+ // This is useful because MSVC link.exe can generate complete PDBs.
+ if (Args.hasArg(OPT_msvclto)) {
+ invokeMSVC(Args);
+ exit(0);
+ }
+
// Do LTO by compiling bitcode input files to a set of native COFF files then
// link those files.
Symtab.addCombinedLTOObjects();
@@ -818,10 +1009,13 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
}
// Handle /safeseh.
- if (Args.hasArg(OPT_safeseh))
+ if (Args.hasArg(OPT_safeseh)) {
for (ObjectFile *File : Symtab.ObjectFiles)
if (!File->SEHCompat)
- fatal("/safeseh: " + File->getName() + " is not compatible with SEH");
+ error("/safeseh: " + File->getName() + " is not compatible with SEH");
+ if (ErrorCount)
+ return;
+ }
// Windows specific -- when we are creating a .dll file, we also
// need to create a .lib file.
@@ -846,17 +1040,6 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// Write the result.
writeResult(&Symtab);
- // Create a symbol map file containing symbol VAs and their names
- // to help debugging.
- std::string MapFile = getMapFile(Args);
- if (!MapFile.empty()) {
- std::error_code EC;
- raw_fd_ostream Out(MapFile, EC, OpenFlags::F_Text);
- if (EC)
- fatal(EC, "could not create the symbol map " + MapFile);
- Symtab.printMap(Out);
- }
-
// Call exit to avoid calling destructors.
exit(0);
}
diff --git a/COFF/Driver.h b/COFF/Driver.h
index 44894269fcbe..4566f73eef31 100644
--- a/COFF/Driver.h
+++ b/COFF/Driver.h
@@ -107,6 +107,8 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
+ void invokeMSVC(llvm::opt::InputArgList &Args);
+
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> MB);
void addBuffer(std::unique_ptr<MemoryBuffer> MB);
void addArchiveBuffer(MemoryBufferRef MBRef, StringRef SymName,
@@ -178,6 +180,8 @@ void checkFailIfMismatch(StringRef Arg);
std::unique_ptr<MemoryBuffer>
convertResToCOFF(const std::vector<MemoryBufferRef> &MBs);
+void runMSVCLinker(std::string Rsp, ArrayRef<StringRef> Objects);
+
// Create enum with OPT_xxx values for each option in Options.td
enum {
OPT_INVALID = 0,
diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp
index 14dd004f1c04..a9c1c9d5593e 100644
--- a/COFF/DriverUtils.cpp
+++ b/COFF/DriverUtils.cpp
@@ -44,31 +44,33 @@ namespace {
class Executor {
public:
explicit Executor(StringRef S) : Saver(Alloc), Prog(Saver.save(S)) {}
- void add(StringRef S) { Args.push_back(Saver.save(S).data()); }
- void add(std::string &S) { Args.push_back(Saver.save(S).data()); }
- void add(Twine S) { Args.push_back(Saver.save(S).data()); }
- void add(const char *S) { Args.push_back(Saver.save(S).data()); }
+ void add(StringRef S) { Args.push_back(Saver.save(S)); }
+ void add(std::string &S) { Args.push_back(Saver.save(S)); }
+ void add(Twine S) { Args.push_back(Saver.save(S)); }
+ void add(const char *S) { Args.push_back(Saver.save(S)); }
void run() {
ErrorOr<std::string> ExeOrErr = sys::findProgramByName(Prog);
if (auto EC = ExeOrErr.getError())
fatal(EC, "unable to find " + Prog + " in PATH: ");
- const char *Exe = Saver.save(*ExeOrErr).data();
+ StringRef Exe = Saver.save(*ExeOrErr);
Args.insert(Args.begin(), Exe);
- Args.push_back(nullptr);
- if (sys::ExecuteAndWait(Args[0], Args.data()) != 0) {
- for (const char *S : Args)
- if (S)
- errs() << S << " ";
- fatal("ExecuteAndWait failed");
- }
+
+ std::vector<const char *> Vec;
+ for (StringRef S : Args)
+ Vec.push_back(S.data());
+ Vec.push_back(nullptr);
+
+ if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0)
+ fatal("ExecuteAndWait failed: " +
+ llvm::join(Args.begin(), Args.end(), " "));
}
private:
BumpPtrAllocator Alloc;
StringSaver Saver;
StringRef Prog;
- std::vector<const char *> Args;
+ std::vector<StringRef> Args;
};
} // anonymous namespace
@@ -167,8 +169,7 @@ void parseMerge(StringRef S) {
if (!Inserted) {
StringRef Existing = Pair.first->second;
if (Existing != To)
- errs() << "warning: " << S << ": already merged into " << Existing
- << "\n";
+ warn(S + ": already merged into " + Existing);
}
}
@@ -282,11 +283,19 @@ static void quoteAndPrint(raw_ostream &Out, StringRef S) {
namespace {
class TemporaryFile {
public:
- TemporaryFile(StringRef Prefix, StringRef Extn) {
+ TemporaryFile(StringRef Prefix, StringRef Extn, StringRef Contents = "") {
SmallString<128> S;
if (auto EC = sys::fs::createTemporaryFile("lld-" + Prefix, Extn, S))
fatal(EC, "cannot create a temporary file");
Path = S.str();
+
+ if (!Contents.empty()) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::F_None);
+ if (EC)
+ fatal(EC, "failed to open " + Path);
+ OS << Contents;
+ }
}
TemporaryFile(TemporaryFile &&Obj) {
@@ -542,7 +551,7 @@ void fixupExports() {
Export *Existing = Pair.first->second;
if (E == *Existing || E.Name != Existing->Name)
continue;
- errs() << "warning: duplicate /export option: " << E.Name << "\n";
+ warn("duplicate /export option: " + E.Name);
}
Config->Exports = std::move(V);
@@ -617,6 +626,26 @@ convertResToCOFF(const std::vector<MemoryBufferRef> &MBs) {
return File.getMemoryBuffer();
}
+// 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) + " ";
+ }
+
+ 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
@@ -653,16 +682,16 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> ArgsArr) {
// Print the real command line if response files are expanded.
if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) {
- outs() << "Command line:";
+ std::string Msg = "Command line:";
for (const char *S : Argv)
- outs() << " " << S;
- outs() << "\n";
+ Msg += " " + std::string(S);
+ message(Msg);
}
if (MissingCount)
fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument");
for (auto *Arg : Args.filtered(OPT_UNKNOWN))
- errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
+ warn("ignoring unknown argument: " + Arg->getSpelling());
return Args;
}
diff --git a/COFF/Error.cpp b/COFF/Error.cpp
index b2bd557413df..b2c7c89bd36c 100644
--- a/COFF/Error.cpp
+++ b/COFF/Error.cpp
@@ -8,11 +8,14 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
+#include "Config.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
+#include <mutex>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
@@ -21,10 +24,68 @@
using namespace llvm;
namespace lld {
+// The functions defined in this file can be called from multiple threads,
+// but outs() or errs() are not thread-safe. We protect them using a mutex.
+static std::mutex Mu;
+
namespace coff {
+StringRef Argv0;
+uint64_t ErrorCount;
+raw_ostream *ErrorOS;
+
+static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
+ // Dealloc/destroy ManagedStatic variables before calling
+ // _exit(). In a non-LTO build, this is a nop. In an LTO
+ // build allows us to get the output of -time-passes.
+ llvm_shutdown();
+
+ outs().flush();
+ errs().flush();
+ _exit(Val);
+}
+
+static void print(StringRef S, raw_ostream::Colors C) {
+ *ErrorOS << Argv0 + ": ";
+ if (Config->ColorDiagnostics) {
+ ErrorOS->changeColor(C, true);
+ *ErrorOS << S;
+ ErrorOS->resetColor();
+ } else {
+ *ErrorOS << S;
+ }
+}
+
+void log(const Twine &Msg) {
+ if (Config->Verbose) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Argv0 << ": " << Msg << "\n";
+ }
+}
+
+void message(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Msg << "\n";
+ outs().flush();
+}
+
+void error(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+
+ if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
+ } else if (ErrorCount == Config->ErrorLimit) {
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << "too many errors emitted, stopping now"
+ << " (use /ERRORLIMIT:0 to see all errors)\n";
+ exitLld(1);
+ }
+
+ ++ErrorCount;
+}
void fatal(const Twine &Msg) {
- if (sys::Process::StandardErrHasColors()) {
+ if (Config->ColorDiagnostics) {
errs().changeColor(raw_ostream::RED, /*bold=*/true);
errs() << "error: ";
errs().resetColor();
@@ -32,10 +93,7 @@ void fatal(const Twine &Msg) {
errs() << "error: ";
}
errs() << Msg << "\n";
-
- outs().flush();
- errs().flush();
- _exit(1);
+ exitLld(1);
}
void fatal(std::error_code EC, const Twine &Msg) {
@@ -46,5 +104,11 @@ void fatal(llvm::Error &Err, const Twine &Msg) {
fatal(errorToErrorCode(std::move(Err)), Msg);
}
+void warn(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ print("warning: ", raw_ostream::MAGENTA);
+ *ErrorOS << Msg << "\n";
+}
+
} // namespace coff
} // namespace lld
diff --git a/COFF/Error.h b/COFF/Error.h
index 47549327db2b..a4f44fb1e36c 100644
--- a/COFF/Error.h
+++ b/COFF/Error.h
@@ -16,11 +16,19 @@
namespace lld {
namespace coff {
+extern uint64_t ErrorCount;
+extern llvm::raw_ostream *ErrorOS;
+extern llvm::StringRef Argv0;
+
+void log(const Twine &Msg);
+void message(const Twine &Msg);
+void warn(const Twine &Msg);
+void error(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
-template <class T> T check(ErrorOr<T> &&V, const Twine &Prefix) {
+template <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);
return std::move(*V);
diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp
index 196fbe2610ea..19468c0fac5e 100644
--- a/COFF/ICF.cpp
+++ b/COFF/ICF.cpp
@@ -231,19 +231,16 @@ void ICF::run(const std::vector<Chunk *> &Vec) {
++Cnt;
} while (Repeat);
- if (Config->Verbose)
- outs() << "\nICF needed " << Cnt << " iterations\n";
+ log("ICF needed " + Twine(Cnt) + " iterations");
// Merge sections in the same colors.
forEachColor([&](size_t Begin, size_t End) {
if (End - Begin == 1)
return;
- if (Config->Verbose)
- outs() << "Selected " << Chunks[Begin]->getDebugName() << "\n";
+ log("Selected " + Chunks[Begin]->getDebugName());
for (size_t I = Begin + 1; I < End; ++I) {
- if (Config->Verbose)
- outs() << " Removed " << Chunks[I]->getDebugName() << "\n";
+ log(" Removed " + Chunks[I]->getDebugName());
Chunks[Begin]->replace(Chunks[I]);
}
});
diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp
index cde355cd3f34..cb56e13014db 100644
--- a/COFF/InputFiles.cpp
+++ b/COFF/InputFiles.cpp
@@ -19,8 +19,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOModule.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/COFF.h"
@@ -41,13 +39,23 @@ using namespace llvm::support::endian;
using llvm::Triple;
using llvm::support::ulittle32_t;
-using llvm::sys::fs::file_magic;
-using llvm::sys::fs::identify_magic;
namespace lld {
namespace coff {
-LLVMContext BitcodeFile::Context;
+/// Checks that Source is compatible with being a weak alias to Target.
+/// If Source is Undefined and has no weak alias set, makes it a weak
+/// alias to Target.
+static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,
+ SymbolBody *Source, SymbolBody *Target) {
+ auto *U = dyn_cast<Undefined>(Source);
+ if (!U)
+ return;
+ else if (!U->WeakAlias)
+ U->WeakAlias = Target;
+ else if (U->WeakAlias != Target)
+ Symtab->reportDuplicate(Source->symbol(), F);
+}
ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@@ -177,15 +185,9 @@ void ObjectFile::initializeSymbols() {
I += Sym.getNumberOfAuxSymbols();
LastSectionNumber = Sym.getSectionNumber();
}
- for (auto WeakAlias : WeakAliases) {
- auto *U = dyn_cast<Undefined>(WeakAlias.first);
- if (!U)
- continue;
- // Report an error if two undefined symbols have different weak aliases.
- if (U->WeakAlias && U->WeakAlias != SparseSymbolBodies[WeakAlias.second])
- Symtab->reportDuplicate(U->symbol(), this);
- U->WeakAlias = SparseSymbolBodies[WeakAlias.second];
- }
+ for (auto WeakAlias : WeakAliases)
+ checkAndSetWeakAlias(Symtab, this, WeakAlias.first,
+ SparseSymbolBodies[WeakAlias.second]);
}
SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) {
@@ -200,7 +202,10 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
if (Sym.isCommon()) {
auto *C = new (Alloc) CommonChunk(Sym);
Chunks.push_back(C);
- return Symtab->addCommon(this, Sym, C)->body();
+ COFFObj->getSymbolName(Sym, Name);
+ Symbol *S =
+ Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C);
+ return S->body();
}
if (Sym.isAbsolute()) {
COFFObj->getSymbolName(Sym, Name);
@@ -247,10 +252,14 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP,
}
DefinedRegular *B;
- if (Sym.isExternal())
- B = cast<DefinedRegular>(Symtab->addRegular(this, Sym, SC)->body());
- else
- B = new (Alloc) DefinedRegular(this, Sym, SC);
+ if (Sym.isExternal()) {
+ COFFObj->getSymbolName(Sym, Name);
+ Symbol *S =
+ Symtab->addRegular(this, Name, SC->isCOMDAT(), Sym.getGeneric(), SC);
+ B = cast<DefinedRegular>(S->body());
+ } else
+ B = new (Alloc) DefinedRegular(this, /*Name*/ "", SC->isCOMDAT(),
+ /*IsExternal*/ false, Sym.getGeneric(), SC);
if (SC->isCOMDAT() && Sym.getValue() == 0 && !AuxP)
SC->setSymbol(B);
@@ -329,39 +338,32 @@ void ImportFile::parse() {
}
void BitcodeFile::parse() {
- Context.enableDebugTypeODRUniquing();
- ErrorOr<std::unique_ptr<LTOModule>> ModOrErr = LTOModule::createFromBuffer(
- Context, MB.getBufferStart(), MB.getBufferSize(), llvm::TargetOptions());
- M = check(std::move(ModOrErr), "could not create LTO module");
-
- StringSaver Saver(Alloc);
- for (unsigned I = 0, E = M->getSymbolCount(); I != E; ++I) {
- lto_symbol_attributes Attrs = M->getSymbolAttributes(I);
- if ((Attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
- continue;
-
- StringRef SymName = Saver.save(M->getSymbolName(I));
- int SymbolDef = Attrs & LTO_SYMBOL_DEFINITION_MASK;
- if (SymbolDef == LTO_SYMBOL_DEFINITION_UNDEFINED) {
- SymbolBodies.push_back(Symtab->addUndefined(SymName, this, false)->body());
+ Obj = check(lto::InputFile::create(MemoryBufferRef(
+ MB.getBuffer(), Saver.save(ParentName + MB.getBufferIdentifier()))));
+ for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) {
+ StringRef SymName = Saver.save(ObjSym.getName());
+ Symbol *Sym;
+ if (ObjSym.isUndefined()) {
+ Sym = Symtab->addUndefined(SymName, this, false);
+ } else if (ObjSym.isCommon()) {
+ Sym = Symtab->addCommon(this, SymName, ObjSym.getCommonSize());
+ } else if (ObjSym.isWeak() && ObjSym.isIndirect()) {
+ // Weak external.
+ Sym = Symtab->addUndefined(SymName, this, true);
+ std::string Fallback = ObjSym.getCOFFWeakExternalFallback();
+ SymbolBody *Alias = Symtab->addUndefined(Saver.save(Fallback));
+ checkAndSetWeakAlias(Symtab, this, Sym->body(), Alias);
} else {
- bool Replaceable =
- (SymbolDef == LTO_SYMBOL_DEFINITION_TENTATIVE || // common
- (Attrs & LTO_SYMBOL_COMDAT) || // comdat
- (SymbolDef == LTO_SYMBOL_DEFINITION_WEAK && // weak external
- (Attrs & LTO_SYMBOL_ALIAS)));
- SymbolBodies.push_back(
- Symtab->addBitcode(this, SymName, Replaceable)->body());
+ bool IsCOMDAT = ObjSym.getComdatIndex() != -1;
+ Sym = Symtab->addRegular(this, SymName, IsCOMDAT);
}
+ SymbolBodies.push_back(Sym->body());
}
-
- Directives = M->getLinkerOpts();
+ Directives = Obj->getCOFFLinkerOpts();
}
MachineTypes BitcodeFile::getMachineType() {
- if (!M)
- return IMAGE_FILE_MACHINE_UNKNOWN;
- switch (Triple(M->getTargetTriple()).getArch()) {
+ switch (Triple(Obj->getTargetTriple()).getArch()) {
case Triple::x86_64:
return AMD64;
case Triple::x86:
diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h
index 1b5d42939cca..9e02b2fc68bb 100644
--- a/COFF/InputFiles.h
+++ b/COFF/InputFiles.h
@@ -13,8 +13,7 @@
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOModule.h"
+#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFF.h"
#include "llvm/Support/StringSaver.h"
@@ -25,7 +24,6 @@
namespace lld {
namespace coff {
-using llvm::LTOModule;
using llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN;
using llvm::COFF::MachineTypes;
using llvm::object::Archive;
@@ -174,7 +172,6 @@ public:
private:
void parse() override;
- llvm::BumpPtrAllocator Alloc;
llvm::BumpPtrAllocator StringAllocAux;
llvm::StringSaver StringAlloc;
@@ -191,16 +188,12 @@ public:
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
std::vector<SymbolBody *> &getSymbols() { return SymbolBodies; }
MachineTypes getMachineType() override;
- std::unique_ptr<LTOModule> takeModule() { return std::move(M); }
-
- static llvm::LLVMContext Context;
+ std::unique_ptr<llvm::lto::InputFile> Obj;
private:
void parse() override;
std::vector<SymbolBody *> SymbolBodies;
- llvm::BumpPtrAllocator Alloc;
- std::unique_ptr<LTOModule> M;
};
} // namespace coff
diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp
new file mode 100644
index 000000000000..6883b3b4c2c8
--- /dev/null
+++ b/COFF/LTO.cpp
@@ -0,0 +1,140 @@
+//===- LTO.cpp ------------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LTO.h"
+#include "Config.h"
+#include "Error.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Config.h"
+#include "llvm/LTO/LTO.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static void diagnosticHandler(const DiagnosticInfo &DI) {
+ SmallString<128> ErrStorage;
+ raw_svector_ostream OS(ErrStorage);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ warn(ErrStorage);
+}
+
+static void checkError(Error E) {
+ handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error {
+ error(EIB.message());
+ return Error::success();
+ });
+}
+
+static void saveBuffer(StringRef Buffer, const Twine &Path) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ error("cannot create " + Path + ": " + EC.message());
+ OS << Buffer;
+}
+
+static std::unique_ptr<lto::LTO> createLTO() {
+ lto::Config Conf;
+ Conf.Options = InitTargetOptionsFromCodeGenFlags();
+ Conf.RelocModel = Reloc::PIC_;
+ Conf.DisableVerify = true;
+ Conf.DiagHandler = diagnosticHandler;
+ Conf.OptLevel = Config->LTOOptLevel;
+ if (Config->SaveTemps)
+ checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
+ /*UseInputModulePath*/ true));
+ lto::ThinBackend Backend;
+ if (Config->LTOJobs != 0)
+ Backend = lto::createInProcessThinBackend(Config->LTOJobs);
+ return llvm::make_unique<lto::LTO>(std::move(Conf), Backend,
+ Config->LTOPartitions);
+}
+
+BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
+
+BitcodeCompiler::~BitcodeCompiler() = default;
+
+static void undefine(Symbol *S) {
+ replaceBody<Undefined>(S, S->body()->getName());
+}
+
+void BitcodeCompiler::add(BitcodeFile &F) {
+ lto::InputFile &Obj = *F.Obj;
+ unsigned SymNum = 0;
+ std::vector<SymbolBody *> SymBodies = F.getSymbols();
+ std::vector<lto::SymbolResolution> Resols(SymBodies.size());
+
+ // Provide a resolution to the LTO API for each symbol.
+ for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) {
+ SymbolBody *B = SymBodies[SymNum];
+ Symbol *Sym = B->symbol();
+ lto::SymbolResolution &R = Resols[SymNum];
+ ++SymNum;
+
+ // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile
+ // reports two symbols for module ASM defined. Without this check, lld
+ // flags an undefined in IR with a definition in ASM as prevailing.
+ // Once IRObjectFile is fixed to report only one symbol this hack can
+ // be removed.
+ R.Prevailing = !ObjSym.isUndefined() && B->getFile() == &F;
+ R.VisibleToRegularObj = Sym->IsUsedInRegularObj;
+ if (R.Prevailing)
+ undefine(Sym);
+ }
+ checkError(LTOObj->add(std::move(F.Obj), Resols));
+}
+
+// Merge all the bitcode files we have seen, codegen the result
+// and return the resulting objects.
+std::vector<StringRef> BitcodeCompiler::compile() {
+ unsigned MaxTasks = LTOObj->getMaxTasks();
+ Buff.resize(MaxTasks);
+
+ checkError(LTOObj->run([&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ }));
+
+ std::vector<StringRef> Ret;
+ for (unsigned I = 0; I != MaxTasks; ++I) {
+ if (Buff[I].empty())
+ continue;
+ if (Config->SaveTemps) {
+ if (I == 0)
+ saveBuffer(Buff[I], Config->OutputFile + ".lto.obj");
+ else
+ saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj");
+ }
+ Ret.emplace_back(Buff[I].data(), Buff[I].size());
+ }
+ return Ret;
+}
diff --git a/COFF/LTO.h b/COFF/LTO.h
new file mode 100644
index 000000000000..194a4cce8ada
--- /dev/null
+++ b/COFF/LTO.h
@@ -0,0 +1,56 @@
+//===- LTO.h ----------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a way to combine bitcode files into one COFF
+// file by compiling them using LLVM.
+//
+// If LTO is in use, your input files are not in regular COFF files
+// but instead LLVM bitcode files. In that case, the linker has to
+// convert bitcode files into the native format so that we can create
+// a COFF file that contains native code. This file provides that
+// functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_LTO_H
+#define LLD_COFF_LTO_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/SmallString.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace lto {
+class LTO;
+}
+}
+
+namespace lld {
+namespace coff {
+
+class BitcodeFile;
+class InputFile;
+
+class BitcodeCompiler {
+public:
+ BitcodeCompiler();
+ ~BitcodeCompiler();
+
+ void add(BitcodeFile &F);
+ std::vector<StringRef> compile();
+
+private:
+ std::unique_ptr<llvm::lto::LTO> LTOObj;
+ std::vector<SmallString<0>> Buff;
+};
+}
+}
+
+#endif
diff --git a/COFF/Librarian.cpp b/COFF/Librarian.cpp
index 4c597fad7345..3ce72822180b 100644
--- a/COFF/Librarian.cpp
+++ b/COFF/Librarian.cpp
@@ -104,7 +104,18 @@ static ImportNameType getNameType(StringRef Sym, StringRef ExtName) {
static std::string replace(StringRef S, StringRef From, StringRef To) {
size_t Pos = S.find(From);
- assert(Pos != StringRef::npos);
+
+ // From and To may be mangled, but substrings in S may not.
+ if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
+ From = From.substr(1);
+ To = To.substr(1);
+ Pos = S.find(From);
+ }
+
+ if (Pos == StringRef::npos) {
+ error(S + ": replacing '" + From + "' with '" + To + "' failed");
+ return "";
+ }
return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
}
diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp
new file mode 100644
index 000000000000..43dd8dc35810
--- /dev/null
+++ b/COFF/MapFile.cpp
@@ -0,0 +1,114 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the /lldmap option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out In File Symbol
+// =================================================================
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 .text
+// 00201000 0000000e 4 test.o
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "Error.h"
+#include "Symbols.h"
+#include "Writer.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::coff;
+
+static void writeOutSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+ uint64_t Align, StringRef Name) {
+ OS << format("%08llx %08llx %5lld ", Address, Size, Align)
+ << left_justify(Name, 7);
+}
+
+static void writeInSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+ uint64_t Align, StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeOutSecLine(OS, Address, Size, Align, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeFileLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+ uint64_t Align, StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeInSecLine(OS, Address, Size, Align, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeSymbolLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
+ StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeFileLine(OS, Address, Size, 0, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeSectionChunk(raw_fd_ostream &OS, const SectionChunk *SC,
+ StringRef &PrevName) {
+ StringRef Name = SC->getSectionName();
+ if (Name != PrevName) {
+ writeInSecLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), Name);
+ OS << '\n';
+ PrevName = Name;
+ }
+ coff::ObjectFile *File = SC->File;
+ if (!File)
+ return;
+ writeFileLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(),
+ toString(File));
+ OS << '\n';
+ ArrayRef<SymbolBody *> Syms = File->getSymbols();
+ for (SymbolBody *Sym : Syms) {
+ auto *DR = dyn_cast<DefinedRegular>(Sym);
+ if (!DR || DR->getChunk() != SC ||
+ DR->getCOFFSymbol().isSectionDefinition())
+ continue;
+ writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym));
+ OS << '\n';
+ }
+}
+
+static void writeMapFile2(raw_fd_ostream &OS,
+ ArrayRef<OutputSection *> OutputSections) {
+ OS << "Address Size Align Out In File Symbol\n";
+
+ for (OutputSection *Sec : OutputSections) {
+ uint32_t VA = Sec->getRVA();
+ writeOutSecLine(OS, VA, Sec->getVirtualSize(), /*Align=*/PageSize,
+ Sec->getName());
+ OS << '\n';
+ StringRef PrevName = "";
+ for (Chunk *C : Sec->getChunks())
+ if (const auto *SC = dyn_cast<SectionChunk>(C))
+ writeSectionChunk(OS, SC, PrevName);
+ }
+}
+
+void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+ if (Config->MapFile.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC)
+ fatal("cannot open " + Config->MapFile + ": " + EC.message());
+ writeMapFile2(OS, OutputSections);
+}
diff --git a/COFF/MapFile.h b/COFF/MapFile.h
new file mode 100644
index 000000000000..0d0d68ce3ead
--- /dev/null
+++ b/COFF/MapFile.h
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_COFF_MAPFILE_H
+#define LLD_COFF_MAPFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+namespace lld {
+namespace coff {
+class OutputSection;
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif
diff --git a/COFF/ModuleDef.cpp b/COFF/ModuleDef.cpp
index a273b6f535db..c9a40ac5ab8c 100644
--- a/COFF/ModuleDef.cpp
+++ b/COFF/ModuleDef.cpp
@@ -163,17 +163,25 @@ private:
case KwHeapsize:
parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
return;
- case KwLibrary:
- parseName(&Config->OutputFile, &Config->ImageBase);
- if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
- Config->OutputFile += ".dll";
- return;
case KwStacksize:
parseNumbers(&Config->StackReserve, &Config->StackCommit);
return;
- case KwName:
- parseName(&Config->OutputFile, &Config->ImageBase);
+ case KwLibrary:
+ case KwName: {
+ bool IsDll = Tok.K == KwLibrary; // Check before parseName.
+ std::string Name;
+ parseName(&Name, &Config->ImageBase);
+
+ // Append the appropriate file extension if not already present.
+ StringRef Ext = IsDll ? ".dll" : ".exe";
+ if (!StringRef(Name).endswith_lower(Ext))
+ Name += Ext;
+
+ // Set the output file, but don't override /out if it was already passed.
+ if (Config->OutputFile.empty())
+ Config->OutputFile = Name;
return;
+ }
case KwVersion:
parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
return;
diff --git a/COFF/Options.td b/COFF/Options.td
index 9dfbcc8e188c..7b5573b31cd3 100644
--- a/COFF/Options.td
+++ b/COFF/Options.td
@@ -21,6 +21,8 @@ def base : P<"base", "Base address of the program">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def delayload : P<"delayload", "Delay loaded DLL name">;
def entry : P<"entry", "Name of entry point symbol">;
+def errorlimit : P<"errorlimit",
+ "Maximum number of errors to emit before stopping (0 = no limit)">;
def export : P<"export", "Export a function">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
@@ -28,6 +30,8 @@ def heap : P<"heap", "Size of the heap">;
def implib : P<"implib", "Import library name">;
def libpath : P<"libpath", "Additional library search path">;
def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">;
+def lldsavetemps : F<"lldsavetemps">,
+ HelpText<"Save temporary files instead of deleting them">;
def machine : P<"machine", "Specify target platform">;
def merge : P<"merge", "Combine sections">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
@@ -78,6 +82,8 @@ def force_unresolved : F<"force:unresolved">;
defm allowbind: B<"allowbind", "Disable DLL binding">;
defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
+defm appcontainer : B<"appcontainer",
+ "Image can only be run in an app container">;
defm dynamicbase : B<"dynamicbase",
"Disable address space layout randomization">;
defm fixed : B<"fixed", "Enable base relocations">;
@@ -91,7 +97,9 @@ def help : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// LLD extensions
+def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">;
def nosymtab : F<"nosymtab">;
+def msvclto : F<"msvclto">;
// Flags for debugging
def debugpdb : F<"debugpdb">;
diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp
index 923fc64c7734..e32bcd20a541 100644
--- a/COFF/PDB.cpp
+++ b/COFF/PDB.cpp
@@ -20,20 +20,23 @@
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/MSF/ByteStream.h"
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
-#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
-#include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStream.h"
-#include "llvm/DebugInfo/PDB/Raw/TpiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
+#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include <memory>
@@ -79,32 +82,49 @@ static ArrayRef<uint8_t> getDebugSection(ObjectFile *File, StringRef SecName) {
return Data.slice(4);
}
-// Merge .debug$T sections and returns it.
-static std::vector<uint8_t> mergeDebugT(SymbolTable *Symtab) {
- ScopedPrinter W(outs());
+static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
+ codeview::TypeTableBuilder &TypeTable) {
+ // Start the TPI or IPI stream header.
+ TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+
+ // Flatten the in memory type table.
+ TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
+ // FIXME: Hash types.
+ TpiBuilder.addTypeRecord(Rec, None);
+ });
+}
+// Merge .debug$T sections into IpiData and TpiData.
+static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,
+ codeview::TypeTableBuilder &TypeTable,
+ codeview::TypeTableBuilder &IDTable) {
// Visit all .debug$T sections to add them to Builder.
- codeview::TypeTableBuilder Builder(BAlloc);
for (ObjectFile *File : Symtab->ObjectFiles) {
ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T");
if (Data.empty())
continue;
- msf::ByteStream Stream(Data);
+ BinaryByteStream Stream(Data, support::little);
codeview::CVTypeArray Types;
- msf::StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
+ // Follow type servers. If the same type server is encountered more than
+ // once for this instance of `PDBTypeServerHandler` (for example if many
+ // object files reference the same TypeServer), the types from the
+ // TypeServer will only be visited once.
+ pdb::PDBTypeServerHandler Handler;
+ Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));
if (auto EC = Reader.readArray(Types, Reader.getLength()))
fatal(EC, "Reader::readArray failed");
- if (!codeview::mergeTypeStreams(Builder, Types))
- fatal("codeview::mergeTypeStreams failed");
+ if (auto Err =
+ codeview::mergeTypeStreams(IDTable, TypeTable, &Handler, Types))
+ fatal(Err, "codeview::mergeTypeStreams failed");
}
- // Construct section contents.
- std::vector<uint8_t> V;
- Builder.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Rec) {
- V.insert(V.end(), Rec.begin(), Rec.end());
- });
- return V;
+ // Construct TPI stream contents.
+ addTypeInfo(Builder.getTpiBuilder(), TypeTable);
+
+ // Construct IPI stream contents.
+ addTypeInfo(Builder.getIpiBuilder(), IDTable);
}
static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
@@ -115,6 +135,8 @@ static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) {
TypeDatabase TDB;
TypeDumpVisitor TDV(TDB, &W, false);
+ // Use a default implementation that does not follow type servers and instead
+ // just dumps the contents of the TypeServer2 record.
CVTypeDumper TypeDumper(TDB);
if (auto EC = TypeDumper.dump(Data, TDV))
fatal(EC, "CVTypeDumper::dump failed");
@@ -126,9 +148,9 @@ static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) {
if (Data.empty())
return;
- msf::ByteStream Stream(Data);
+ BinaryByteStream Stream(Data, llvm::support::little);
CVSymbolArray Symbols;
- msf::StreamReader Reader(Stream);
+ BinaryStreamReader Reader(Stream);
if (auto EC = Reader.readArray(Symbols, Reader.getLength()))
fatal(EC, "StreamReader.readArray<CVSymbolArray> failed");
@@ -148,17 +170,6 @@ static void dumpCodeView(SymbolTable *Symtab) {
}
}
-static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,
- ArrayRef<uint8_t> Data) {
- msf::ByteStream Stream(Data);
- codeview::CVTypeArray Records;
- msf::StreamReader Reader(Stream);
- if (auto EC = Reader.readArray(Records, Reader.getLength()))
- fatal(EC, "Reader.readArray failed");
- for (const codeview::CVType &Rec : Records)
- TpiBuilder.addTypeRecord(Rec);
-}
-
// Creates a PDB file.
void coff::createPDB(StringRef Path, SymbolTable *Symtab,
ArrayRef<uint8_t> SectionTable,
@@ -177,9 +188,12 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
// Add an Info stream.
auto &InfoBuilder = Builder.getInfoBuilder();
- InfoBuilder.setAge(DI->PDB70.Age);
- InfoBuilder.setGuid(
- *reinterpret_cast<const pdb::PDB_UniqueId *>(&DI->PDB70.Signature));
+ InfoBuilder.setAge(DI ? DI->PDB70.Age : 0);
+
+ pdb::PDB_UniqueId uuid{};
+ if (DI)
+ memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid));
+ InfoBuilder.setGuid(uuid);
// Should be the current time, but set 0 for reproducibilty.
InfoBuilder.setSignature(0);
InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70);
@@ -188,18 +202,9 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
auto &DbiBuilder = Builder.getDbiBuilder();
DbiBuilder.setVersionHeader(pdb::PdbDbiV110);
- // Add an empty TPI stream.
- auto &TpiBuilder = Builder.getTpiBuilder();
- TpiBuilder.setVersionHeader(pdb::PdbTpiV80);
- std::vector<uint8_t> TpiData;
- if (Config->DebugPdb) {
- TpiData = mergeDebugT(Symtab);
- addTypeInfo(TpiBuilder, TpiData);
- }
-
- // Add an empty IPI stream.
- auto &IpiBuilder = Builder.getIpiBuilder();
- IpiBuilder.setVersionHeader(pdb::PdbTpiV80);
+ codeview::TypeTableBuilder TypeTable(BAlloc);
+ codeview::TypeTableBuilder IDTable(BAlloc);
+ mergeDebugT(Symtab, Builder, TypeTable, IDTable);
// Add Section Contributions.
std::vector<pdb::SectionContrib> Contribs =
@@ -214,7 +219,7 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab,
pdb::DbiStreamBuilder::createSectionMap(Sections);
DbiBuilder.setSectionMap(SectionMap);
- ExitOnErr(DbiBuilder.addModuleInfo("", "* Linker *"));
+ ExitOnErr(DbiBuilder.addModuleInfo("* Linker *"));
// Add COFF section header stream.
ExitOnErr(
diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp
index 9cc0b75c1510..310eab274526 100644
--- a/COFF/SymbolTable.cpp
+++ b/COFF/SymbolTable.cpp
@@ -11,10 +11,10 @@
#include "Config.h"
#include "Driver.h"
#include "Error.h"
+#include "LTO.h"
#include "Memory.h"
#include "Symbols.h"
#include "llvm/IR/LLVMContext.h"
-#include "llvm/LTO/legacy/LTOCodeGenerator.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <utility>
@@ -24,11 +24,40 @@ using namespace llvm;
namespace lld {
namespace coff {
+enum SymbolPreference {
+ SP_EXISTING = -1,
+ SP_CONFLICT = 0,
+ SP_NEW = 1,
+};
+
+/// Checks if an existing symbol S should be kept or replaced by a new symbol.
+/// Returns SP_EXISTING when S should be kept, SP_NEW when the new symbol
+/// should be kept, and SP_CONFLICT if no valid resolution exists.
+static SymbolPreference compareDefined(Symbol *S, bool WasInserted,
+ bool NewIsCOMDAT) {
+ // If the symbol wasn't previously known, the new symbol wins by default.
+ if (WasInserted || !isa<Defined>(S->body()))
+ return SP_NEW;
+
+ // If the existing symbol is a DefinedRegular, both it and the new symbol
+ // must be comdats. In that case, we have no reason to prefer one symbol
+ // over the other, and we keep the existing one. If one of the symbols
+ // is not a comdat, we report a conflict.
+ if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
+ if (NewIsCOMDAT && R->isCOMDAT())
+ return SP_EXISTING;
+ else
+ return SP_CONFLICT;
+ }
+
+ // Existing symbol is not a DefinedRegular; new symbol wins.
+ return SP_NEW;
+}
+
SymbolTable *Symtab;
void SymbolTable::addFile(InputFile *File) {
- if (Config->Verbose)
- outs() << "Reading " << toString(File) << "\n";
+ log("Reading " + toString(File));
File->parse();
MachineTypes MT = File->getMachineType();
@@ -51,8 +80,7 @@ void SymbolTable::addFile(InputFile *File) {
if (S.empty())
return;
- if (Config->Verbose)
- outs() << "Directives: " << toString(File) << ": " << S << "\n";
+ log("Directives: " + toString(File) + ": " + S);
Driver->parseDirectives(S);
}
@@ -106,12 +134,11 @@ void SymbolTable::reportRemainingUndefines() {
return;
for (SymbolBody *B : Config->GCRoot)
if (Undefs.count(B))
- errs() << "<root>: undefined symbol: " << B->getName() << "\n";
+ warn("<root>: undefined symbol: " + B->getName());
for (ObjectFile *File : ObjectFiles)
for (SymbolBody *Sym : File->getSymbols())
if (Undefs.count(Sym))
- errs() << toString(File) << ": undefined symbol: " << Sym->getName()
- << "\n";
+ warn(toString(File) + ": undefined symbol: " + Sym->getName());
if (!Config->Force)
fatal("link failed");
}
@@ -163,7 +190,7 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol Sym) {
}
void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
- fatal("duplicate symbol: " + toString(*Existing->body()) + " in " +
+ error("duplicate symbol: " + toString(*Existing->body()) + " in " +
toString(Existing->body()->getFile()) + " and in " +
(NewFile ? toString(NewFile) : "(internal)"));
}
@@ -204,59 +231,35 @@ Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) {
return S;
}
-Symbol *SymbolTable::addRegular(ObjectFile *F, COFFSymbolRef Sym,
+Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ const coff_symbol_generic *Sym,
SectionChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
- Symbol *S;
- bool WasInserted;
- std::tie(S, WasInserted) = insert(Name);
- S->IsUsedInRegularObj = true;
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body()))
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (auto *R = dyn_cast<DefinedRegular>(S->body())) {
- if (!C->isCOMDAT() || !R->isCOMDAT())
- reportDuplicate(S, F);
- } else if (auto *B = dyn_cast<DefinedBitcode>(S->body())) {
- if (B->IsReplaceable)
- replaceBody<DefinedRegular>(S, F, Sym, C);
- else if (!C->isCOMDAT())
- reportDuplicate(S, F);
- } else
- replaceBody<DefinedRegular>(S, F, Sym, C);
- return S;
-}
-
-Symbol *SymbolTable::addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable) {
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(N);
- if (WasInserted || isa<Undefined>(S->body()) || isa<Lazy>(S->body())) {
- replaceBody<DefinedBitcode>(S, F, N, IsReplaceable);
- return S;
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
+ SymbolPreference SP = compareDefined(S, WasInserted, IsCOMDAT);
+ if (SP == SP_CONFLICT) {
+ reportDuplicate(S, F);
+ } else if (SP == SP_NEW) {
+ replaceBody<DefinedRegular>(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C);
}
- if (isa<DefinedCommon>(S->body()))
- return S;
- if (IsReplaceable)
- if (isa<DefinedRegular>(S->body()) || isa<DefinedBitcode>(S->body()))
- return S;
- reportDuplicate(S, F);
return S;
}
-Symbol *SymbolTable::addCommon(ObjectFile *F, COFFSymbolRef Sym,
- CommonChunk *C) {
- StringRef Name;
- F->getCOFFObj()->getSymbolName(Sym, Name);
+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(Name);
- S->IsUsedInRegularObj = true;
+ std::tie(S, WasInserted) = insert(N);
+ if (!isa<BitcodeFile>(F))
+ S->IsUsedInRegularObj = true;
if (WasInserted || !isa<DefinedCOFF>(S->body()))
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
else if (auto *DC = dyn_cast<DefinedCommon>(S->body()))
- if (Sym.getValue() > DC->getSize())
- replaceBody<DefinedCommon>(S, F, Sym, C);
+ if (Size > DC->getSize())
+ replaceBody<DefinedCommon>(S, F, N, Size, Sym, C);
return S;
}
@@ -345,75 +348,21 @@ SymbolBody *SymbolTable::addUndefined(StringRef Name) {
return addUndefined(Name, nullptr, false)->body();
}
-void SymbolTable::printMap(llvm::raw_ostream &OS) {
- for (ObjectFile *File : ObjectFiles) {
- OS << toString(File) << ":\n";
- for (SymbolBody *Body : File->getSymbols())
- if (auto *R = dyn_cast<DefinedRegular>(Body))
- if (R->getChunk()->isLive())
- OS << Twine::utohexstr(Config->ImageBase + R->getRVA())
- << " " << R->getName() << "\n";
- }
+std::vector<StringRef> SymbolTable::compileBitcodeFiles() {
+ LTO.reset(new BitcodeCompiler);
+ for (BitcodeFile *F : BitcodeFiles)
+ LTO->add(*F);
+ return LTO->compile();
}
void SymbolTable::addCombinedLTOObjects() {
if (BitcodeFiles.empty())
return;
-
- // Create an object file and add it to the symbol table by replacing any
- // DefinedBitcode symbols with the definitions in the object file.
- LTOCodeGenerator CG(BitcodeFile::Context);
- CG.setOptLevel(Config->LTOOptLevel);
- for (ObjectFile *Obj : createLTOObjects(&CG))
+ for (StringRef Object : compileBitcodeFiles()) {
+ auto *Obj = make<ObjectFile>(MemoryBufferRef(Object, "lto.tmp"));
Obj->parse();
-}
-
-// Combine and compile bitcode files and then return the result
-// as a vector of regular COFF object files.
-std::vector<ObjectFile *> SymbolTable::createLTOObjects(LTOCodeGenerator *CG) {
- // All symbols referenced by non-bitcode objects, including GC roots, must be
- // preserved. We must also replace bitcode symbols with undefined symbols so
- // that they may be replaced with real definitions without conflicting.
- for (BitcodeFile *File : BitcodeFiles)
- for (SymbolBody *Body : File->getSymbols()) {
- if (!isa<DefinedBitcode>(Body))
- continue;
- if (Body->symbol()->IsUsedInRegularObj)
- CG->addMustPreserveSymbol(Body->getName());
- replaceBody<Undefined>(Body->symbol(), Body->getName());
- }
-
- CG->setModule(BitcodeFiles[0]->takeModule());
- for (unsigned I = 1, E = BitcodeFiles.size(); I != E; ++I)
- CG->addModule(BitcodeFiles[I]->takeModule().get());
-
- bool DisableVerify = true;
-#ifdef NDEBUG
- DisableVerify = false;
-#endif
- if (!CG->optimize(DisableVerify, false, false, false))
- fatal(""); // optimize() should have emitted any error message.
-
- Objs.resize(Config->LTOJobs);
- // Use std::list to avoid invalidation of pointers in OSPtrs.
- std::list<raw_svector_ostream> OSs;
- std::vector<raw_pwrite_stream *> OSPtrs;
- for (SmallString<0> &Obj : Objs) {
- OSs.emplace_back(Obj);
- OSPtrs.push_back(&OSs.back());
+ ObjectFiles.push_back(Obj);
}
-
- if (!CG->compileOptimized(OSPtrs))
- fatal(""); // compileOptimized() should have emitted any error message.
-
- std::vector<ObjectFile *> ObjFiles;
- for (SmallString<0> &Obj : Objs) {
- auto *ObjFile = make<ObjectFile>(MemoryBufferRef(Obj, "<LTO object>"));
- ObjectFiles.push_back(ObjFile);
- ObjFiles.push_back(ObjFile);
- }
-
- return ObjFiles;
}
} // namespace coff
diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h
index 703821f2e124..764dd5318775 100644
--- a/COFF/SymbolTable.h
+++ b/COFF/SymbolTable.h
@@ -11,6 +11,7 @@
#define LLD_COFF_SYMBOL_TABLE_H
#include "InputFiles.h"
+#include "LTO.h"
#include "llvm/ADT/CachedHashString.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
@@ -69,13 +70,11 @@ public:
void mangleMaybe(SymbolBody *B);
StringRef findMangle(StringRef Name);
- // Print a layout map to OS.
- void printMap(llvm::raw_ostream &OS);
-
// Build a set of COFF objects representing the combined contents of
// BitcodeFiles and add them to the symbol table. Called after all files are
// added and before the writer writes results to a file.
void addCombinedLTOObjects();
+ std::vector<StringRef> compileBitcodeFiles();
// The writer needs to handle DLL import libraries specially in
// order to create the import descriptor table.
@@ -93,9 +92,12 @@ public:
Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias);
void addLazy(ArchiveFile *F, const Archive::Symbol Sym);
Symbol *addAbsolute(StringRef N, COFFSymbolRef S);
- Symbol *addRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C);
- Symbol *addBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable);
- Symbol *addCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C);
+ Symbol *addRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr);
+ Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size,
+ const llvm::object::coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr);
Symbol *addImportData(StringRef N, ImportFile *F);
Symbol *addImportThunk(StringRef Name, DefinedImportData *S,
uint16_t Machine);
@@ -113,12 +115,11 @@ private:
StringRef findByPrefix(StringRef Prefix);
void addCombinedLTOObject(ObjectFile *Obj);
- std::vector<ObjectFile *> createLTOObjects(llvm::LTOCodeGenerator *CG);
llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab;
std::vector<BitcodeFile *> BitcodeFiles;
- std::vector<SmallString<0>> Objs;
+ std::unique_ptr<BitcodeCompiler> LTO;
};
extern SymbolTable *Symtab;
diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp
index c44537d37135..993e920ce7f7 100644
--- a/COFF/Symbols.cpp
+++ b/COFF/Symbols.cpp
@@ -30,7 +30,7 @@ namespace lld {
namespace coff {
StringRef SymbolBody::getName() {
- // DefinedCOFF names are read lazily for a performance reason.
+ // COFF symbol names are read lazily for a performance reason.
// Non-external symbol names are never used by the linker except for logging
// or debugging. Their internal references are resolved not by name but by
// symbol index. And because they are not external, no one can refer them by
@@ -39,7 +39,7 @@ StringRef SymbolBody::getName() {
// is a waste of time.
if (Name.empty()) {
auto *D = cast<DefinedCOFF>(this);
- D->File->getCOFFObj()->getSymbolName(D->Sym, Name);
+ cast<ObjectFile>(D->File)->getCOFFObj()->getSymbolName(D->Sym, Name);
}
return Name;
}
@@ -47,15 +47,14 @@ StringRef SymbolBody::getName() {
InputFile *SymbolBody::getFile() {
if (auto *Sym = dyn_cast<DefinedCOFF>(this))
return Sym->File;
- if (auto *Sym = dyn_cast<DefinedBitcode>(this))
- return Sym->File;
if (auto *Sym = dyn_cast<Lazy>(this))
return Sym->File;
return nullptr;
}
COFFSymbolRef DefinedCOFF::getCOFFSymbol() {
- size_t SymSize = File->getCOFFObj()->getSymbolTableEntrySize();
+ size_t SymSize =
+ cast<ObjectFile>(File)->getCOFFObj()->getSymbolTableEntrySize();
if (SymSize == sizeof(coff_symbol16))
return COFFSymbolRef(reinterpret_cast<const coff_symbol16 *>(Sym));
assert(SymSize == sizeof(coff_symbol32));
diff --git a/COFF/Symbols.h b/COFF/Symbols.h
index 1ca7366364d7..1b83f73ff20c 100644
--- a/COFF/Symbols.h
+++ b/COFF/Symbols.h
@@ -30,7 +30,6 @@ using llvm::object::coff_import_header;
using llvm::object::coff_symbol_generic;
class ArchiveFile;
-class BitcodeFile;
class InputFile;
class ObjectFile;
struct Symbol;
@@ -52,13 +51,12 @@ public:
DefinedImportDataKind,
DefinedAbsoluteKind,
DefinedRelativeKind,
- DefinedBitcodeKind,
UndefinedKind,
LazyKind,
LastDefinedCOFFKind = DefinedCommonKind,
- LastDefinedKind = DefinedBitcodeKind,
+ LastDefinedKind = DefinedRelativeKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -81,7 +79,7 @@ protected:
friend SymbolTable;
explicit SymbolBody(Kind K, StringRef N = "")
: SymbolKind(K), IsExternal(true), IsCOMDAT(false),
- IsReplaceable(false), WrittenToSymtab(false), Name(N) {}
+ WrittenToSymtab(false), Name(N) {}
const unsigned SymbolKind : 8;
unsigned IsExternal : 1;
@@ -89,11 +87,9 @@ protected:
// This bit is used by the \c DefinedRegular subclass.
unsigned IsCOMDAT : 1;
- // This bit is used by the \c DefinedBitcode subclass.
- unsigned IsReplaceable : 1;
-
public:
- // This bit is used by Writer::createSymbolAndStringTable().
+ // This bit is used by Writer::createSymbolAndStringTable() to prevent
+ // symbols from being written to the symbol table more than once.
unsigned WrittenToSymtab : 1;
protected:
@@ -104,7 +100,7 @@ protected:
// etc.
class Defined : public SymbolBody {
public:
- Defined(Kind K, StringRef N = "") : SymbolBody(K, N) {}
+ Defined(Kind K, StringRef N) : SymbolBody(K, N) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedKind;
@@ -127,22 +123,25 @@ public:
bool isExecutable();
};
-// Symbols defined via a COFF object file.
+// Symbols defined via a COFF object file or bitcode file. For COFF files, this
+// stores a coff_symbol_generic*, and names of internal symbols are lazily
+// loaded through that. For bitcode files, Sym is nullptr and the name is stored
+// as a StringRef.
class DefinedCOFF : public Defined {
friend SymbolBody;
public:
- DefinedCOFF(Kind K, ObjectFile *F, COFFSymbolRef S)
- : Defined(K), File(F), Sym(S.getGeneric()) {}
+ DefinedCOFF(Kind K, InputFile *F, StringRef N, const coff_symbol_generic *S)
+ : Defined(K, N), File(F), Sym(S) {}
static bool classof(const SymbolBody *S) {
return S->kind() <= LastDefinedCOFFKind;
}
- ObjectFile *getFile() { return File; }
+ InputFile *getFile() { return File; }
COFFSymbolRef getCOFFSymbol();
- ObjectFile *File;
+ InputFile *File;
protected:
const coff_symbol_generic *Sym;
@@ -151,10 +150,13 @@ protected:
// Regular defined symbols read from object file symbol tables.
class DefinedRegular : public DefinedCOFF {
public:
- DefinedRegular(ObjectFile *F, COFFSymbolRef S, SectionChunk *C)
- : DefinedCOFF(DefinedRegularKind, F, S), Data(&C->Repl) {
- IsExternal = S.isExternal();
- IsCOMDAT = C->isCOMDAT();
+ DefinedRegular(InputFile *F, StringRef N, bool IsCOMDAT,
+ bool IsExternal = false,
+ const coff_symbol_generic *S = nullptr,
+ SectionChunk *C = nullptr)
+ : DefinedCOFF(DefinedRegularKind, F, N, S), Data(C ? &C->Repl : nullptr) {
+ this->IsExternal = IsExternal;
+ this->IsCOMDAT = IsCOMDAT;
}
static bool classof(const SymbolBody *S) {
@@ -172,9 +174,11 @@ private:
class DefinedCommon : public DefinedCOFF {
public:
- DefinedCommon(ObjectFile *F, COFFSymbolRef S, CommonChunk *C)
- : DefinedCOFF(DefinedCommonKind, F, S), Data(C) {
- IsExternal = S.isExternal();
+ DefinedCommon(InputFile *F, StringRef N, uint64_t Size,
+ const coff_symbol_generic *S = nullptr,
+ CommonChunk *C = nullptr)
+ : DefinedCOFF(DefinedCommonKind, F, N, S), Data(C), Size(Size) {
+ this->IsExternal = true;
}
static bool classof(const SymbolBody *S) {
@@ -185,8 +189,9 @@ public:
private:
friend SymbolTable;
- uint64_t getSize() { return Sym->Value; }
+ uint64_t getSize() const { return Size; }
CommonChunk *Data;
+ uint64_t Size;
};
// Absolute symbols.
@@ -340,26 +345,6 @@ private:
LocalImportChunk *Data;
};
-class DefinedBitcode : public Defined {
- friend SymbolBody;
-public:
- DefinedBitcode(BitcodeFile *F, StringRef N, bool IsReplaceable)
- : Defined(DefinedBitcodeKind, N), File(F) {
- // IsReplaceable tracks whether the bitcode symbol may be replaced with some
- // other (defined, common or bitcode) symbol. This is the case for common,
- // comdat and weak external symbols. We try to replace bitcode symbols with
- // "real" symbols (see SymbolTable::add{Regular,Bitcode}), and resolve the
- // result against the real symbol from the combined LTO object.
- this->IsReplaceable = IsReplaceable;
- }
-
- static bool classof(const SymbolBody *S) {
- return S->kind() == DefinedBitcodeKind;
- }
-
- BitcodeFile *File;
-};
-
inline uint64_t Defined::getRVA() {
switch (kind()) {
case DefinedAbsoluteKind:
@@ -376,8 +361,6 @@ inline uint64_t Defined::getRVA() {
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
- case DefinedBitcodeKind:
- llvm_unreachable("There is no address for a bitcode symbol.");
case LazyKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
@@ -401,10 +384,9 @@ struct Symbol {
// This field is used to store the Symbol's SymbolBody. This instantiation of
// AlignedCharArrayUnion gives us a struct with a char array field that is
// large and aligned enough to store any derived class of SymbolBody.
- llvm::AlignedCharArrayUnion<DefinedRegular, DefinedCommon, DefinedAbsolute,
- DefinedRelative, Lazy, Undefined,
- DefinedImportData, DefinedImportThunk,
- DefinedLocalImport, DefinedBitcode>
+ llvm::AlignedCharArrayUnion<
+ DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy,
+ Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport>
Body;
SymbolBody *body() {
diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp
index 71217ebeb60a..8762b88c4d6b 100644
--- a/COFF/Writer.cpp
+++ b/COFF/Writer.cpp
@@ -12,6 +12,7 @@
#include "DLL.h"
#include "Error.h"
#include "InputFiles.h"
+#include "MapFile.h"
#include "Memory.h"
#include "PDB.h"
#include "SymbolTable.h"
@@ -39,7 +40,6 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::coff;
-static const int PageSize = 4096;
static const int SectorSize = 512;
static const int DOSStubSize = 64;
static const int NumberfOfDataDirectory = 16;
@@ -163,51 +163,6 @@ namespace coff {
void writeResult(SymbolTable *T) { Writer(T).run(); }
-// OutputSection represents a section in an output file. It's a
-// container of chunks. OutputSection and Chunk are 1:N relationship.
-// Chunks cannot belong to more than one OutputSections. The writer
-// creates multiple OutputSections and assign them unique,
-// non-overlapping file offsets and RVAs.
-class OutputSection {
-public:
- OutputSection(StringRef N) : Name(N), Header({}) {}
- void setRVA(uint64_t);
- void setFileOffset(uint64_t);
- void addChunk(Chunk *C);
- StringRef getName() { return Name; }
- std::vector<Chunk *> &getChunks() { return Chunks; }
- void addPermissions(uint32_t C);
- void setPermissions(uint32_t C);
- uint32_t getPermissions() { return Header.Characteristics & PermMask; }
- uint32_t getCharacteristics() { return Header.Characteristics; }
- uint64_t getRVA() { return Header.VirtualAddress; }
- uint64_t getFileOff() { return Header.PointerToRawData; }
- void writeHeaderTo(uint8_t *Buf);
-
- // Returns the size of this section in an executable memory image.
- // This may be smaller than the raw size (the raw size is multiple
- // of disk sector size, so there may be padding at end), or may be
- // larger (if that's the case, the loader reserves spaces after end
- // of raw data).
- uint64_t getVirtualSize() { return Header.VirtualSize; }
-
- // Returns the size of the section in the output file.
- uint64_t getRawSize() { return Header.SizeOfRawData; }
-
- // Set offset into the string table storing this section name.
- // Used only when the name is longer than 8 bytes.
- void setStringTableOff(uint32_t V) { StringTableOff = V; }
-
- // N.B. The section index is one based.
- uint32_t SectionIndex = 0;
-
-private:
- StringRef Name;
- coff_section Header;
- uint32_t StringTableOff = 0;
- std::vector<Chunk *> Chunks;
-};
-
void OutputSection::setRVA(uint64_t RVA) {
Header.VirtualAddress = RVA;
for (Chunk *C : Chunks)
@@ -303,8 +258,14 @@ void Writer::run() {
sortExceptionTable();
writeBuildId();
- if (!Config->PDBPath.empty())
- createPDB(Config->PDBPath, Symtab, SectionTable, BuildId->DI);
+ if (!Config->PDBPath.empty()) {
+ const llvm::codeview::DebugInfo *DI = nullptr;
+ if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV))
+ DI = BuildId->DI;
+ createPDB(Config->PDBPath, Symtab, SectionTable, DI);
+ }
+
+ writeMapFile(OutputSections);
if (auto EC = Buffer->commit())
fatal(EC, "failed to write the output file");
@@ -641,6 +602,8 @@ template <typename PEHeaderTy> void Writer::writeHeader() {
PE->SizeOfStackCommit = Config->StackCommit;
PE->SizeOfHeapReserve = Config->HeapReserve;
PE->SizeOfHeapCommit = Config->HeapCommit;
+ if (Config->AppContainer)
+ PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_APPCONTAINER;
if (Config->DynamicBase)
PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE;
if (Config->HighEntropyVA)
@@ -830,7 +793,7 @@ void Writer::writeBuildId() {
"only PDB 7.0 is supported");
assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) &&
"signature size mismatch");
- memcpy(BuildId->DI->PDB70.Signature, Res,
+ memcpy(BuildId->DI->PDB70.Signature, Res.Bytes.data(),
sizeof(codeview::PDB70DebugInfo::Signature));
// TODO(compnerd) track the Age
BuildId->DI->PDB70.Age = 1;
diff --git a/COFF/Writer.h b/COFF/Writer.h
index 0d26090177d8..fef575423878 100644
--- a/COFF/Writer.h
+++ b/COFF/Writer.h
@@ -10,14 +10,65 @@
#ifndef LLD_COFF_WRITER_H
#define LLD_COFF_WRITER_H
+#include "Chunks.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include <cstdint>
#include <vector>
namespace lld {
namespace coff {
class SymbolTable;
+static const int PageSize = 4096;
+
void writeResult(SymbolTable *T);
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and RVAs.
+class OutputSection {
+public:
+ OutputSection(llvm::StringRef N) : Name(N), Header({}) {}
+ void setRVA(uint64_t);
+ void setFileOffset(uint64_t);
+ void addChunk(Chunk *C);
+ llvm::StringRef getName() { return Name; }
+ std::vector<Chunk *> &getChunks() { return Chunks; }
+ void addPermissions(uint32_t C);
+ void setPermissions(uint32_t C);
+ uint32_t getPermissions() { return Header.Characteristics & PermMask; }
+ uint32_t getCharacteristics() { return Header.Characteristics; }
+ uint64_t getRVA() { return Header.VirtualAddress; }
+ uint64_t getFileOff() { return Header.PointerToRawData; }
+ void writeHeaderTo(uint8_t *Buf);
+
+ // Returns the size of this section in an executable memory image.
+ // This may be smaller than the raw size (the raw size is multiple
+ // of disk sector size, so there may be padding at end), or may be
+ // larger (if that's the case, the loader reserves spaces after end
+ // of raw data).
+ uint64_t getVirtualSize() { return Header.VirtualSize; }
+
+ // Returns the size of the section in the output file.
+ uint64_t getRawSize() { return Header.SizeOfRawData; }
+
+ // Set offset into the string table storing this section name.
+ // Used only when the name is longer than 8 bytes.
+ void setStringTableOff(uint32_t V) { StringTableOff = V; }
+
+ // N.B. The section index is one based.
+ uint32_t SectionIndex = 0;
+
+private:
+ llvm::StringRef Name;
+ llvm::object::coff_section Header;
+ uint32_t StringTableOff = 0;
+ std::vector<Chunk *> Chunks;
+};
+
}
}
diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt
index 2e9d2b941fd9..41da497abe26 100644
--- a/ELF/CMakeLists.txt
+++ b/ELF/CMakeLists.txt
@@ -11,16 +11,19 @@ add_lld_library(lldELF
DriverUtils.cpp
EhFrame.cpp
Error.cpp
+ Filesystem.cpp
GdbIndex.cpp
ICF.cpp
InputFiles.cpp
InputSection.cpp
LTO.cpp
LinkerScript.cpp
+ MapFile.cpp
MarkLive.cpp
Mips.cpp
OutputSections.cpp
Relocations.cpp
+ ScriptLexer.cpp
ScriptParser.cpp
Strings.cpp
SymbolTable.cpp
@@ -53,7 +56,7 @@ add_lld_library(lldELF
LINK_LIBS
lldConfig
lldCore
- ${PTHREAD_LIB}
+ ${LLVM_PTHREAD_LIB}
DEPENDS
ELFOptionsTableGen
diff --git a/ELF/Config.h b/ELF/Config.h
index b7706205a5b6..c8eecec7439c 100644
--- a/ELF/Config.h
+++ b/ELF/Config.h
@@ -13,7 +13,10 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/CachePruning.h"
+#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ELF.h"
+#include "llvm/Support/Endian.h"
#include <vector>
@@ -34,14 +37,14 @@ enum ELFKind {
// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
-// For --discard-{all,locals,none} and --retain-symbols-file.
-enum class DiscardPolicy { Default, All, Locals, RetainFile, None };
+// For --discard-{all,locals,none}.
+enum class DiscardPolicy { Default, All, Locals, None };
// For --strip-{all,debug}.
enum class StripPolicy { None, All, Debug };
// For --unresolved-symbols.
-enum class UnresolvedPolicy { NoUndef, ReportError, Warn, Ignore };
+enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll };
// For --sort-section and linkerscript sorting rules.
enum class SortSectionPolicy { Default, None, Alignment, Name, Priority };
@@ -58,11 +61,10 @@ struct SymbolVersion {
// This struct contains symbols version definition that
// can be found in version script if it is used for link.
struct VersionDefinition {
- VersionDefinition(llvm::StringRef Name, uint16_t Id) : Name(Name), Id(Id) {}
llvm::StringRef Name;
- uint16_t Id;
+ uint16_t Id = 0;
std::vector<SymbolVersion> Globals;
- size_t NameOff; // Offset in string table.
+ size_t NameOff = 0; // Offset in the string table
};
// This struct contains the global configuration for the linker.
@@ -72,6 +74,7 @@ struct VersionDefinition {
struct Configuration {
InputFile *FirstElf = nullptr;
uint8_t OSABI = 0;
+ llvm::CachePruningPolicy ThinLTOCachePolicy;
llvm::StringMap<uint64_t> SectionStartMap;
llvm::StringRef DynamicLinker;
llvm::StringRef Entry;
@@ -80,10 +83,12 @@ struct Configuration {
llvm::StringRef Init;
llvm::StringRef LTOAAPipeline;
llvm::StringRef LTONewPmPasses;
+ llvm::StringRef MapFile;
llvm::StringRef OutputFile;
+ llvm::StringRef OptRemarksFilename;
llvm::StringRef SoName;
llvm::StringRef Sysroot;
- llvm::StringSet<> RetainSymbolsFile;
+ llvm::StringRef ThinLTOCacheDir;
std::string RPath;
std::vector<VersionDefinition> VersionDefinitions;
std::vector<llvm::StringRef> AuxiliaryList;
@@ -94,6 +99,7 @@ struct Configuration {
std::vector<SymbolVersion> VersionScriptLocals;
std::vector<uint8_t> BuildIdVector;
bool AllowMultipleDefinition;
+ bool ArchiveWithoutSymbolsSeen = false;
bool AsNeeded = false;
bool Bsymbolic;
bool BsymbolicFunctions;
@@ -102,30 +108,29 @@ struct Configuration {
bool Demangle = true;
bool DisableVerify;
bool EhFrameHdr;
+ bool EmitRelocs;
bool EnableNewDtags;
bool ExportDynamic;
bool FatalWarnings;
bool GcSections;
bool GdbIndex;
- bool GnuHash = false;
+ bool GnuHash;
bool ICF;
- bool Mips64EL = false;
bool MipsN32Abi = false;
bool NoGnuUnique;
bool NoUndefinedVersion;
bool Nostdlib;
bool OFormatBinary;
- bool OMagic;
- bool Pic;
+ bool Omagic;
+ bool OptRemarksWithHotness;
bool Pie;
bool PrintGcSections;
- bool Rela;
bool Relocatable;
bool SaveTemps;
bool SingleRoRx;
bool Shared;
bool Static = false;
- bool SysvHash = true;
+ bool SysvHash;
bool Target1Rel;
bool Threads;
bool Trace;
@@ -134,17 +139,20 @@ struct Configuration {
bool WarnMissingEntry;
bool ZCombreloc;
bool ZExecstack;
+ bool ZNocopyreloc;
bool ZNodelete;
+ bool ZNodlopen;
bool ZNow;
bool ZOrigin;
bool ZRelro;
+ bool ZText;
bool ExitEarly;
bool ZWxneeded;
DiscardPolicy Discard;
SortSectionPolicy SortSection;
- StripPolicy Strip = StripPolicy::None;
+ StripPolicy Strip;
UnresolvedPolicy UnresolvedSymbols;
- Target2Policy Target2 = Target2Policy::GotRel;
+ Target2Policy Target2;
BuildIdKind BuildId = BuildIdKind::None;
ELFKind EKind = ELFNoneKind;
uint16_t DefaultSymbolVersion = llvm::ELF::VER_NDX_GLOBAL;
@@ -157,6 +165,58 @@ struct Configuration {
unsigned LTOO;
unsigned Optimize;
unsigned ThinLTOJobs;
+
+ // The following config options do not directly correspond to any
+ // particualr command line options.
+
+ // True if we need to pass through relocations in input files to the
+ // output file. Usually false because we consume relocations.
+ bool CopyRelocs;
+
+ // True if the target is ELF64. False if ELF32.
+ bool Is64;
+
+ // True if the target is little-endian. False if big-endian.
+ bool IsLE;
+
+ // endianness::little if IsLE is true. endianness::big otherwise.
+ llvm::support::endianness Endianness;
+
+ // True if the target is the little-endian MIPS64.
+ //
+ // The reason why we have this variable only for the MIPS is because
+ // we use this often. Some ELF headers for MIPS64EL are in a
+ // mixed-endian (which is horrible and I'd say that's a serious spec
+ // bug), and we need to know whether we are reading MIPS ELF files or
+ // not in various places.
+ //
+ // (Note that MIPS64EL is not a typo for MIPS64LE. This is the official
+ // name whatever that means. A fun hypothesis is that "EL" is short for
+ // little-endian written in the little-endian order, but I don't know
+ // if that's true.)
+ bool IsMips64EL;
+
+ // The ELF spec defines two types of relocation table entries, RELA and
+ // REL. RELA is a triplet of (offset, info, addend) while REL is a
+ // tuple of (offset, info). Addends for REL are implicit and read from
+ // the location where the relocations are applied. So, REL is more
+ // compact than RELA but requires a bit of more work to process.
+ //
+ // (From the linker writer's view, this distinction is not necessary.
+ // If the ELF had chosen whichever and sticked with it, it would have
+ // been easier to write code to process relocations, but it's too late
+ // to change the spec.)
+ //
+ // Each ABI defines its relocation type. IsRela is true if target
+ // uses RELA. As far as we know, all 64-bit ABIs are using RELA. A
+ // few 32-bit ABIs are using RELA too.
+ bool IsRela;
+
+ // True if we are creating position-independent code.
+ bool Pic;
+
+ // 4 for ELF32, 8 for ELF64.
+ int Wordsize;
};
// The only instance of Configuration struct.
diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp
index 50b701175d3e..47ecd607a48f 100644
--- a/ELF/Driver.cpp
+++ b/ELF/Driver.cpp
@@ -6,15 +6,34 @@
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
+//
+// The driver drives the entire linking process. It is responsible for
+// parsing command line options and doing whatever it is instructed to do.
+//
+// One notable thing in the LLD's driver when compared to other linkers is
+// that the LLD's driver is agnostic on the host operating system.
+// Other linkers usually have implicit default values (such as a dynamic
+// linker path or library paths) for each host OS.
+//
+// I don't think implicit default values are useful because they are
+// usually explicitly specified by the compiler driver. They can even
+// be harmful when you are doing cross-linking. Therefore, in LLD, we
+// simply trust the compiler driver to pass all required options and
+// don't try to make effort on our side.
+//
+//===----------------------------------------------------------------------===//
#include "Driver.h"
#include "Config.h"
#include "Error.h"
+#include "Filesystem.h"
#include "ICF.h"
#include "InputFiles.h"
#include "InputSection.h"
#include "LinkerScript.h"
#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Target.h"
@@ -48,16 +67,19 @@ BumpPtrAllocator elf::BAlloc;
StringSaver elf::Saver{BAlloc};
std::vector<SpecificAllocBase *> elf::SpecificAllocBase::Instances;
+static void setConfigs();
+
bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly,
raw_ostream &Error) {
ErrorCount = 0;
ErrorOS = &Error;
Argv0 = Args[0];
+ InputSections.clear();
Tar = nullptr;
Config = make<Configuration>();
Driver = make<LinkerDriver>();
- ScriptConfig = make<ScriptConfiguration>();
+ Script = make<LinkerScript>();
Driver->main(Args, CanExitEarly);
freeArena();
@@ -78,10 +100,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) {
.Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64})
.Case("armelf_linux_eabi", {ELF32LEKind, EM_ARM})
.Case("elf32_x86_64", {ELF32LEKind, EM_X86_64})
- .Case("elf32btsmip", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmip", {ELF32LEKind, EM_MIPS})
- .Case("elf32btsmipn32", {ELF32BEKind, EM_MIPS})
- .Case("elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
+ .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS})
+ .Cases("elf32ltsmip", "elf32ltsmipn32", {ELF32LEKind, EM_MIPS})
.Case("elf32ppc", {ELF32BEKind, EM_PPC})
.Case("elf64btsmip", {ELF64BEKind, EM_MIPS})
.Case("elf64ltsmip", {ELF64LEKind, EM_MIPS})
@@ -133,7 +153,7 @@ LinkerDriver::getArchiveMembers(MemoryBufferRef MB) {
// Opens and parses a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
-void LinkerDriver::addFile(StringRef Path) {
+void LinkerDriver::addFile(StringRef Path, bool WithLOption) {
using namespace sys::fs;
Optional<MemoryBufferRef> Buffer = readFile(Path);
@@ -164,6 +184,19 @@ void LinkerDriver::addFile(StringRef Path) {
return;
}
Files.push_back(createSharedFile(MBRef));
+
+ // DSOs usually have DT_SONAME tags in their ELF headers, and the
+ // sonames are used to identify DSOs. But if they are missing,
+ // they are identified by filenames. We don't know whether the new
+ // file has a DT_SONAME or not because we haven't parsed it yet.
+ // Here, we set the default soname for the file because we might
+ // need it later.
+ //
+ // If a file was specified by -lfoo, the directory part is not
+ // significant, as a user did not specify it. This behavior is
+ // compatible with GNU.
+ Files.back()->DefaultSoName =
+ WithLOption ? sys::path::filename(Path) : Path;
return;
default:
if (InLib)
@@ -176,7 +209,7 @@ void LinkerDriver::addFile(StringRef Path) {
// Add a given library by searching it from input search paths.
void LinkerDriver::addLibrary(StringRef Name) {
if (Optional<std::string> Path = searchLibrary(Name))
- addFile(*Path);
+ addFile(*Path, /*WithLOption=*/true);
else
error("unable to find library -l" + Name);
}
@@ -281,11 +314,27 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
return;
}
- // GNU linkers disagree here. Though both -version and -v are mentioned
- // in help to print the version information, GNU ld just normally exits,
- // while gold can continue linking. We are compatible with ld.bfd here.
- if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v))
- outs() << getLLDVersion() << "\n";
+ // Handle -v or -version.
+ //
+ // A note about "compatible with GNU linkers" message: this is a hack for
+ // scripts generated by GNU Libtool 2.4.6 (released in February 2014 and
+ // still the newest version in March 2017) or earlier to recognize LLD as
+ // a GNU compatible linker. As long as an output for the -v option
+ // contains "GNU" or "with BFD", they recognize us as GNU-compatible.
+ //
+ // This is somewhat ugly hack, but in reality, we had no choice other
+ // than doing this. Considering the very long release cycle of Libtool,
+ // it is not easy to improve it to recognize LLD as a GNU compatible
+ // linker in a timely manner. Even if we can make it, there are still a
+ // lot of "configure" scripts out there that are generated by old version
+ // of Libtool. We cannot convince every software developer to migrate to
+ // the latest version and re-generate scripts. So we have this hack.
+ if (Args.hasArg(OPT_v) || Args.hasArg(OPT_version))
+ message(getLLDVersion() + " (compatible with GNU linkers)");
+
+ // ld.bfd always exits after printing out the version string.
+ // ld.gold proceeds if a given option is -v. Because gold's behavior
+ // is more permissive than ld.bfd, we chose what gold does here.
if (Args.hasArg(OPT_version))
return;
@@ -311,6 +360,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
initLLVM(Args);
createFiles(Args);
inferMachineType();
+ setConfigs();
checkOptions(Args);
if (ErrorCount)
return;
@@ -333,26 +383,68 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) {
}
}
-static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) {
+static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
+ bool Default) {
+ if (auto *Arg = Args.getLastArg(K1, K2))
+ return Arg->getOption().getID() == K1;
+ return Default;
+}
+
+static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
+ std::vector<StringRef> V;
+ for (auto *Arg : Args.filtered(Id))
+ V.push_back(Arg->getValue());
+ return V;
+}
+
+static std::string getRPath(opt::InputArgList &Args) {
+ std::vector<StringRef> V = getArgs(Args, OPT_rpath);
+ return llvm::join(V.begin(), V.end(), ":");
+}
+
+// Determines what we should do if there are remaining unresolved
+// symbols after the name resolution.
+static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) {
+ // -noinhibit-exec or -r imply some default values.
if (Args.hasArg(OPT_noinhibit_exec))
- return UnresolvedPolicy::Warn;
- if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"))
- return UnresolvedPolicy::NoUndef;
- if (Config->Relocatable)
- return UnresolvedPolicy::Ignore;
+ return UnresolvedPolicy::WarnAll;
+ if (Args.hasArg(OPT_relocatable))
+ return UnresolvedPolicy::IgnoreAll;
- if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) {
- StringRef S = Arg->getValue();
- if (S == "ignore-all" || S == "ignore-in-object-files")
- return UnresolvedPolicy::Ignore;
- if (S == "ignore-in-shared-libs" || S == "report-all")
- return UnresolvedPolicy::ReportError;
- error("unknown --unresolved-symbols value: " + S);
+ UnresolvedPolicy ErrorOrWarn = getArg(Args, OPT_error_unresolved_symbols,
+ OPT_warn_unresolved_symbols, true)
+ ? UnresolvedPolicy::ReportError
+ : UnresolvedPolicy::Warn;
+
+ // Process the last of -unresolved-symbols, -no-undefined or -z defs.
+ for (auto *Arg : llvm::reverse(Args)) {
+ switch (Arg->getOption().getID()) {
+ case OPT_unresolved_symbols: {
+ StringRef S = Arg->getValue();
+ if (S == "ignore-all" || S == "ignore-in-object-files")
+ return UnresolvedPolicy::Ignore;
+ if (S == "ignore-in-shared-libs" || S == "report-all")
+ return ErrorOrWarn;
+ error("unknown --unresolved-symbols value: " + S);
+ continue;
+ }
+ case OPT_no_undefined:
+ return ErrorOrWarn;
+ case OPT_z:
+ if (StringRef(Arg->getValue()) == "defs")
+ return ErrorOrWarn;
+ continue;
+ }
}
- return UnresolvedPolicy::ReportError;
+
+ // -shared implies -unresolved-symbols=ignore-all because missing
+ // symbols are likely to be resolved at runtime using other DSOs.
+ if (Config->Shared)
+ return UnresolvedPolicy::Ignore;
+ return ErrorOrWarn;
}
-static Target2Policy getTarget2Option(opt::InputArgList &Args) {
+static Target2Policy getTarget2(opt::InputArgList &Args) {
if (auto *Arg = Args.getLastArg(OPT_target2)) {
StringRef S = Arg->getValue();
if (S == "rel")
@@ -376,16 +468,10 @@ static bool isOutputFormatBinary(opt::InputArgList &Args) {
return false;
}
-static bool getArg(opt::InputArgList &Args, unsigned K1, unsigned K2,
- bool Default) {
- if (auto *Arg = Args.getLastArg(K1, K2))
- return Arg->getOption().getID() == K1;
- return Default;
-}
-
-static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
- if (Config->Relocatable)
+static DiscardPolicy getDiscard(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
return DiscardPolicy::None;
+
auto *Arg =
Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
if (!Arg)
@@ -397,13 +483,23 @@ static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
return DiscardPolicy::None;
}
-static StripPolicy getStripOption(opt::InputArgList &Args) {
- if (auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug)) {
- if (Arg->getOption().getID() == OPT_strip_all)
- return StripPolicy::All;
- return StripPolicy::Debug;
- }
- return StripPolicy::None;
+static StringRef getDynamicLinker(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
+ if (!Arg || Arg->getOption().getID() == OPT_no_dynamic_linker)
+ return "";
+ return Arg->getValue();
+}
+
+static StripPolicy getStrip(opt::InputArgList &Args) {
+ if (Args.hasArg(OPT_relocatable))
+ return StripPolicy::None;
+
+ auto *Arg = Args.getLastArg(OPT_strip_all, OPT_strip_debug);
+ if (!Arg)
+ return StripPolicy::None;
+ if (Arg->getOption().getID() == OPT_strip_all)
+ return StripPolicy::All;
+ return StripPolicy::Debug;
}
static uint64_t parseSectionAddress(StringRef S, opt::Arg *Arg) {
@@ -433,7 +529,7 @@ static StringMap<uint64_t> getSectionStartMap(opt::InputArgList &Args) {
return Ret;
}
-static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
+static SortSectionPolicy getSortSection(opt::InputArgList &Args) {
StringRef S = getString(Args, OPT_sort_section);
if (S == "alignment")
return SortSectionPolicy::Alignment;
@@ -444,6 +540,17 @@ static SortSectionPolicy getSortKind(opt::InputArgList &Args) {
return SortSectionPolicy::Default;
}
+static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {
+ StringRef S = getString(Args, OPT_hash_style, "sysv");
+ if (S == "sysv")
+ return {true, false};
+ if (S == "gnu")
+ return {false, true};
+ if (S != "both")
+ error("unknown -hash-style: " + S);
+ return {true, true};
+}
+
static std::vector<StringRef> getLines(MemoryBufferRef MB) {
SmallVector<StringRef, 0> Arr;
MB.getBuffer().split(Arr, '\n');
@@ -459,116 +566,112 @@ static std::vector<StringRef> getLines(MemoryBufferRef MB) {
// Initializes Config members by the command line options.
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
- for (auto *Arg : Args.filtered(OPT_L))
- Config->SearchPaths.push_back(Arg->getValue());
-
- std::vector<StringRef> RPaths;
- for (auto *Arg : Args.filtered(OPT_rpath))
- RPaths.push_back(Arg->getValue());
- if (!RPaths.empty())
- Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":");
-
- if (auto *Arg = Args.getLastArg(OPT_m)) {
- // Parse ELF{32,64}{LE,BE} and CPU type.
- StringRef S = Arg->getValue();
- std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
- parseEmulation(S);
- Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
- Config->Emulation = S;
- }
-
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
+ Config->AuxiliaryList = getArgs(Args, OPT_auxiliary);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
+ !Args.hasArg(OPT_relocatable));
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
+ Config->Discard = getDiscard(Args);
+ Config->DynamicLinker = getDynamicLinker(Args);
Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
+ Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
- Config->ExportDynamic = Args.hasArg(OPT_export_dynamic);
- Config->FatalWarnings = Args.hasArg(OPT_fatal_warnings);
+ Config->Entry = getString(Args, OPT_entry);
+ Config->ExportDynamic =
+ getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false);
+ Config->FatalWarnings =
+ getArg(Args, OPT_fatal_warnings, OPT_no_fatal_warnings, false);
+ Config->Fini = getString(Args, OPT_fini, "_fini");
Config->GcSections = getArg(Args, OPT_gc_sections, OPT_no_gc_sections, false);
Config->GdbIndex = Args.hasArg(OPT_gdb_index);
Config->ICF = Args.hasArg(OPT_icf);
+ Config->Init = getString(Args, OPT_init, "_init");
+ Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
+ Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
+ Config->LTOO = getInteger(Args, OPT_lto_O, 2);
+ Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
+ Config->MapFile = getString(Args, OPT_Map);
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
Config->Nostdlib = Args.hasArg(OPT_nostdlib);
- Config->OMagic = Args.hasArg(OPT_omagic);
+ Config->OFormatBinary = isOutputFormatBinary(Args);
+ Config->Omagic = Args.hasArg(OPT_omagic);
+ Config->OptRemarksFilename = getString(Args, OPT_opt_remarks_filename);
+ Config->OptRemarksWithHotness = Args.hasArg(OPT_opt_remarks_with_hotness);
+ Config->Optimize = getInteger(Args, OPT_O, 1);
+ Config->OutputFile = getString(Args, OPT_o);
Config->Pie = getArg(Args, OPT_pie, OPT_nopie, false);
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
+ Config->RPath = getRPath(Args);
Config->Relocatable = Args.hasArg(OPT_relocatable);
- Config->DefineCommon = getArg(Args, OPT_define_common, OPT_no_define_common,
- !Config->Relocatable);
- Config->Discard = getDiscardOption(Args);
Config->SaveTemps = Args.hasArg(OPT_save_temps);
- Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SearchPaths = getArgs(Args, OPT_L);
+ Config->SectionStartMap = getSectionStartMap(Args);
Config->Shared = Args.hasArg(OPT_shared);
+ Config->SingleRoRx = Args.hasArg(OPT_no_rosegment);
+ Config->SoName = getString(Args, OPT_soname);
+ Config->SortSection = getSortSection(Args);
+ Config->Strip = getStrip(Args);
+ Config->Sysroot = getString(Args, OPT_sysroot);
Config->Target1Rel = getArg(Args, OPT_target1_rel, OPT_target1_abs, false);
+ Config->Target2 = getTarget2(Args);
+ Config->ThinLTOCacheDir = getString(Args, OPT_thinlto_cache_dir);
+ Config->ThinLTOCachePolicy =
+ check(parseCachePruningPolicy(getString(Args, OPT_thinlto_cache_policy)),
+ "--thinlto-cache-policy: invalid cache policy");
+ Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
Config->Threads = getArg(Args, OPT_threads, OPT_no_threads, true);
Config->Trace = Args.hasArg(OPT_trace);
+ Config->Undefined = getArgs(Args, OPT_undefined);
+ Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args);
Config->Verbose = Args.hasArg(OPT_verbose);
Config->WarnCommon = Args.hasArg(OPT_warn_common);
+ Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
+ Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->ZNodelete = hasZOption(Args, "nodelete");
+ Config->ZNodlopen = hasZOption(Args, "nodlopen");
+ Config->ZNow = hasZOption(Args, "now");
+ Config->ZOrigin = hasZOption(Args, "origin");
+ Config->ZRelro = !hasZOption(Args, "norelro");
+ Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);
+ Config->ZText = !hasZOption(Args, "notext");
+ Config->ZWxneeded = hasZOption(Args, "wxneeded");
- Config->DynamicLinker = getString(Args, OPT_dynamic_linker);
- Config->Entry = getString(Args, OPT_entry);
- Config->Fini = getString(Args, OPT_fini, "_fini");
- Config->Init = getString(Args, OPT_init, "_init");
- Config->LTOAAPipeline = getString(Args, OPT_lto_aa_pipeline);
- Config->LTONewPmPasses = getString(Args, OPT_lto_newpm_passes);
- Config->OutputFile = getString(Args, OPT_o);
- Config->SoName = getString(Args, OPT_soname);
- Config->Sysroot = getString(Args, OPT_sysroot);
-
- Config->Optimize = getInteger(Args, OPT_O, 1);
- Config->LTOO = getInteger(Args, OPT_lto_O, 2);
if (Config->LTOO > 3)
error("invalid optimization level for LTO: " + getString(Args, OPT_lto_O));
- Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1);
if (Config->LTOPartitions == 0)
error("--lto-partitions: number of threads must be > 0");
- Config->ThinLTOJobs = getInteger(Args, OPT_thinlto_jobs, -1u);
if (Config->ThinLTOJobs == 0)
error("--thinlto-jobs: number of threads must be > 0");
- Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
- Config->ZExecstack = hasZOption(Args, "execstack");
- Config->ZNodelete = hasZOption(Args, "nodelete");
- Config->ZNow = hasZOption(Args, "now");
- Config->ZOrigin = hasZOption(Args, "origin");
- Config->ZRelro = !hasZOption(Args, "norelro");
- Config->ZStackSize = getZOptionValue(Args, "stack-size", -1);
- Config->ZWxneeded = hasZOption(Args, "wxneeded");
+ if (auto *Arg = Args.getLastArg(OPT_m)) {
+ // Parse ELF{32,64}{LE,BE} and CPU type.
+ StringRef S = Arg->getValue();
+ std::tie(Config->EKind, Config->EMachine, Config->OSABI) =
+ parseEmulation(S);
+ Config->MipsN32Abi = (S == "elf32btsmipn32" || S == "elf32ltsmipn32");
+ Config->Emulation = S;
+ }
- Config->OFormatBinary = isOutputFormatBinary(Args);
- Config->SectionStartMap = getSectionStartMap(Args);
- Config->SortSection = getSortKind(Args);
- Config->Target2 = getTarget2Option(Args);
- Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
+ if (Args.hasArg(OPT_print_map))
+ Config->MapFile = "-";
// --omagic is an option to create old-fashioned executables in which
// .text segments are writable. Today, the option is still in use to
// create special-purpose programs such as boot loaders. It doesn't
// make sense to create PT_GNU_RELRO for such executables.
- if (Config->OMagic)
+ if (Config->Omagic)
Config->ZRelro = false;
- if (!Config->Relocatable)
- Config->Strip = getStripOption(Args);
-
- // Config->Pic is true if we are generating position-independent code.
- Config->Pic = Config->Pie || Config->Shared;
-
- if (auto *Arg = Args.getLastArg(OPT_hash_style)) {
- StringRef S = Arg->getValue();
- if (S == "gnu") {
- Config->GnuHash = true;
- Config->SysvHash = false;
- } else if (S == "both") {
- Config->GnuHash = true;
- } else if (S != "sysv")
- error("unknown hash style: " + S);
- }
+ std::tie(Config->SysvHash, Config->GnuHash) = getHashStyle(Args);
- // Parse --build-id or --build-id=<style>.
+ // Parse --build-id or --build-id=<style>. We handle "tree" as a
+ // synonym for "sha1" because all of our hash functions including
+ // -build-id=sha1 are tree hashes for performance reasons.
if (Args.hasArg(OPT_build_id))
Config->BuildId = BuildIdKind::Fast;
if (auto *Arg = Args.getLastArg(OPT_build_id_eq)) {
@@ -589,15 +692,10 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
}
}
- for (auto *Arg : Args.filtered(OPT_auxiliary))
- Config->AuxiliaryList.push_back(Arg->getValue());
if (!Config->Shared && !Config->AuxiliaryList.empty())
error("-f may not be used without -shared");
- for (auto *Arg : Args.filtered(OPT_undefined))
- Config->Undefined.push_back(Arg->getValue());
-
- if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
+ for (auto *Arg : Args.filtered(OPT_dynamic_list))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
readDynamicList(*Buffer);
@@ -605,13 +703,14 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
Config->SymbolOrderingFile = getLines(*Buffer);
- // If --retain-symbol-file is used, we'll retail only the symbols listed in
+ // If --retain-symbol-file is used, we'll keep only the symbols listed in
// the file and discard all others.
if (auto *Arg = Args.getLastArg(OPT_retain_symbols_file)) {
- Config->Discard = DiscardPolicy::RetainFile;
+ Config->DefaultSymbolVersion = VER_NDX_LOCAL;
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
for (StringRef S : getLines(*Buffer))
- Config->RetainSymbolsFile.insert(S);
+ Config->VersionScriptGlobals.push_back(
+ {S, /*IsExternCpp*/ false, /*HasWildcard*/ false});
}
for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol))
@@ -627,11 +726,37 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
Config->DefaultSymbolVersion = VER_NDX_LOCAL;
}
+ if (getArg(Args, OPT_export_dynamic, OPT_no_export_dynamic, false))
+ Config->DefaultSymbolVersion = VER_NDX_GLOBAL;
+
if (auto *Arg = Args.getLastArg(OPT_version_script))
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
readVersionScript(*Buffer);
}
+// 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() {
+ ELFKind Kind = Config->EKind;
+ uint16_t Machine = Config->EMachine;
+
+ // There is an ILP32 ABI for x86-64, although it's not very popular.
+ // It is called the x32 ABI.
+ bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64);
+
+ Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs);
+ Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind);
+ Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind);
+ Config->Endianness =
+ Config->IsLE ? support::endianness::little : support::endianness::big;
+ Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS);
+ Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi;
+ Config->Pic = Config->Pie || Config->Shared;
+ Config->Wordsize = Config->Is64 ? 8 : 4;
+}
+
// Returns a value of "-format" option.
static bool getBinaryOption(StringRef S) {
if (S == "binary")
@@ -650,7 +775,7 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
addLibrary(Arg->getValue());
break;
case OPT_INPUT:
- addFile(Arg->getValue());
+ addFile(Arg->getValue(), /*WithLOption=*/false);
break;
case OPT_alias_script_T:
case OPT_script:
@@ -744,12 +869,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
SymbolTable<ELFT> Symtab;
elf::Symtab<ELFT>::X = &Symtab;
Target = createTarget();
- ScriptBase = Script<ELFT>::X = make<LinkerScript<ELFT>>();
- Config->Rela =
- ELFT::Is64Bits || Config->EMachine == EM_X86_64 || Config->MipsN32Abi;
- Config->Mips64EL =
- (Config->EMachine == EM_MIPS && Config->EKind == ELF64LEKind);
Config->MaxPageSize = getMaxPageSize(Args);
Config->ImageBase = getImageBase(Args);
@@ -757,6 +877,14 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (Config->OutputFile.empty())
Config->OutputFile = "a.out";
+ // Fail early if the output file or map file is not writable. If a user has a
+ // long link, e.g. due to a large LTO link, they do not wish to run it and
+ // find that it failed because there was a mistake in their command-line.
+ if (!isFileWritable(Config->OutputFile, "output file"))
+ return;
+ if (!isFileWritable(Config->MapFile, "map file"))
+ return;
+
// Use default entry point name if no name was given via the command
// line nor linker scripts. For some reason, MIPS entry point name is
// different from others.
@@ -792,6 +920,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
if (ErrorCount)
return;
+ // 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->Opt.ReferencedSymbols)
+ Symtab.addUndefined(Sym);
+
for (auto *Arg : Args.filtered(OPT_wrap))
Symtab.wrap(Arg->getValue());
@@ -799,12 +932,12 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// Beyond this point, no new files are added.
// Aggregate all input sections into one place.
for (elf::ObjectFile<ELFT> *F : Symtab.getObjectFiles())
- for (InputSectionBase<ELFT> *S : F->getSections())
- if (S && S != &InputSection<ELFT>::Discarded)
- Symtab.Sections.push_back(S);
+ for (InputSectionBase *S : F->getSections())
+ if (S && S != &InputSection::Discarded)
+ InputSections.push_back(S);
for (BinaryFile *F : Symtab.getBinaryFiles())
- for (InputSectionData *S : F->getSections())
- Symtab.Sections.push_back(cast<InputSection<ELFT>>(S));
+ for (InputSectionBase *S : F->getSections())
+ InputSections.push_back(cast<InputSection>(S));
// Do size optimizations: garbage collection and identical code folding.
if (Config->GcSections)
@@ -814,15 +947,15 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
// MergeInputSection::splitIntoPieces needs to be called before
// any call of MergeInputSection::getOffset. Do that.
- forEach(Symtab.Sections.begin(), Symtab.Sections.end(),
- [](InputSectionBase<ELFT> *S) {
- if (!S->Live)
- return;
- if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
- S->uncompress();
- if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(S))
- MS->splitIntoPieces();
- });
+ parallelForEach(InputSections.begin(), InputSections.end(),
+ [](InputSectionBase *S) {
+ if (!S->Live)
+ return;
+ if (Decompressor::isCompressedELFSection(S->Flags, S->Name))
+ S->uncompress();
+ if (auto *MS = dyn_cast<MergeInputSection>(S))
+ MS->splitIntoPieces();
+ });
// Write the result to the file.
writeResult<ELFT>();
diff --git a/ELF/Driver.h b/ELF/Driver.h
index 8bb2093e86ca..6a75a8942ca0 100644
--- a/ELF/Driver.h
+++ b/ELF/Driver.h
@@ -27,7 +27,7 @@ extern class LinkerDriver *Driver;
class LinkerDriver {
public:
void main(ArrayRef<const char *> Args, bool CanExitEarly);
- void addFile(StringRef Path);
+ void addFile(StringRef Path, bool WithLOption);
void addLibrary(StringRef Name);
private:
diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp
index 3a20cd76efe2..f4eadeee9e43 100644
--- a/ELF/DriverUtils.cpp
+++ b/ELF/DriverUtils.cpp
@@ -16,7 +16,6 @@
#include "Driver.h"
#include "Error.h"
#include "Memory.h"
-#include "ScriptParser.h"
#include "lld/Config/Version.h"
#include "lld/Core/Reproduce.h"
#include "llvm/ADT/Optional.h"
@@ -54,12 +53,10 @@ ELFOptTable::ELFOptTable() : OptTable(OptInfo) {}
// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
static bool getColorDiagnostics(opt::InputArgList &Args) {
- bool Default = (ErrorOS == &errs() && Process::StandardErrHasColors());
-
auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
OPT_no_color_diagnostics);
if (!Arg)
- return Default;
+ return ErrorOS->has_colors();
if (Arg->getOption().getID() == OPT_color_diagnostics)
return true;
if (Arg->getOption().getID() == OPT_no_color_diagnostics)
@@ -67,7 +64,7 @@ static bool getColorDiagnostics(opt::InputArgList &Args) {
StringRef S = Arg->getValue();
if (S == "auto")
- return Default;
+ return ErrorOS->has_colors();
if (S == "always")
return true;
if (S != "never")
@@ -120,6 +117,20 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) {
void elf::printHelp(const char *Argv0) {
ELFOptTable Table;
Table.PrintHelp(outs(), Argv0, "lld", false);
+ outs() << "\n";
+
+ // Scripts generated by Libtool versions up to at least 2.4.6 (the most
+ // recent version as of March 2017) expect /: supported targets:.* elf/
+ // in a message for the -help option. If it doesn't match, the scripts
+ // assume that the linker doesn't support very basic features such as
+ // shared libraries. Therefore, we need to print out at least "elf".
+ // Here, we print out all the targets that we support.
+ outs() << Argv0 << ": supported targets: "
+ << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips "
+ << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips "
+ << "elf32-tradlittlemips elf32-x86-64 "
+ << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips "
+ << "elf64-tradlittlemips elf64-x86-64\n";
}
// Reconstructs command line arguments so that so that you can re-run
@@ -136,6 +147,13 @@ std::string elf::createResponseFile(const opt::InputArgList &Args) {
case OPT_INPUT:
OS << quote(rewritePath(Arg->getValue())) << "\n";
break;
+ case OPT_o:
+ // If -o path contains directories, "lld @response.txt" will likely
+ // fail because the archive we are creating doesn't contain empty
+ // directories for the output path (-o doesn't create directories).
+ // Strip directories to prevent the issue.
+ OS << "-o " << quote(sys::path::filename(Arg->getValue())) << "\n";
+ break;
case OPT_L:
case OPT_dynamic_list:
case OPT_rpath:
diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp
index 2428473d9012..90be30a5f0f9 100644
--- a/ELF/EhFrame.cpp
+++ b/ELF/EhFrame.cpp
@@ -38,13 +38,14 @@ using namespace lld::elf;
namespace {
template <class ELFT> class EhReader {
public:
- EhReader(InputSectionBase<ELFT> *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
+ EhReader(InputSectionBase *S, ArrayRef<uint8_t> D) : IS(S), D(D) {}
size_t readEhRecordSize();
uint8_t getFdeEncoding();
private:
template <class P> void failOn(const P *Loc, const Twine &Msg) {
- fatal(IS->getLocation((const uint8_t *)Loc - IS->Data.data()) + ": " + Msg);
+ fatal("corrupted .eh_frame: " + Msg + "\n>>> defined in " +
+ IS->getObjMsg<ELFT>((const uint8_t *)Loc - IS->Data.data()));
}
uint8_t readByte();
@@ -53,15 +54,16 @@ private:
void skipLeb128();
void skipAugP();
- InputSectionBase<ELFT> *IS;
+ InputSectionBase *IS;
ArrayRef<uint8_t> D;
};
}
template <class ELFT>
-size_t elf::readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off) {
+size_t elf::readEhRecordSize(InputSectionBase *S, size_t Off) {
return EhReader<ELFT>(S, S->Data.slice(Off)).readEhRecordSize();
}
+
// .eh_frame section is a sequence of records. Each record starts with
// a 4 byte length field. This function reads the length.
template <class ELFT> size_t EhReader<ELFT>::readEhRecordSize() {
@@ -121,11 +123,11 @@ template <class ELFT> void EhReader<ELFT>::skipLeb128() {
failOn(ErrPos, "corrupted CIE (failed to read LEB128)");
}
-template <class ELFT> static size_t getAugPSize(unsigned Enc) {
+static size_t getAugPSize(unsigned Enc) {
switch (Enc & 0x0f) {
case DW_EH_PE_absptr:
case DW_EH_PE_signed:
- return ELFT::Is64Bits ? 8 : 4;
+ return Config->Wordsize;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
return 2;
@@ -143,7 +145,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
uint8_t Enc = readByte();
if ((Enc & 0xf0) == DW_EH_PE_aligned)
failOn(D.data() - 1, "DW_EH_PE_aligned encoding is not supported");
- size_t Size = getAugPSize<ELFT>(Enc);
+ size_t Size = getAugPSize(Enc);
if (Size == 0)
failOn(D.data() - 1, "unknown FDE encoding");
if (Size >= D.size())
@@ -152,7 +154,7 @@ template <class ELFT> void EhReader<ELFT>::skipAugP() {
}
template <class ELFT> uint8_t elf::getFdeEncoding(EhSectionPiece *P) {
- auto *IS = static_cast<InputSectionBase<ELFT> *>(P->ID);
+ auto *IS = static_cast<InputSectionBase *>(P->ID);
return EhReader<ELFT>(IS, P->data()).getFdeEncoding();
}
@@ -199,14 +201,10 @@ template <class ELFT> uint8_t EhReader<ELFT>::getFdeEncoding() {
return DW_EH_PE_absptr;
}
-template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase<ELF32LE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase<ELF32BE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase<ELF64LE> *S,
- size_t Off);
-template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase<ELF64BE> *S,
- size_t Off);
+template size_t elf::readEhRecordSize<ELF32LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF32BE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64LE>(InputSectionBase *S, size_t Off);
+template size_t elf::readEhRecordSize<ELF64BE>(InputSectionBase *S, size_t Off);
template uint8_t elf::getFdeEncoding<ELF32LE>(EhSectionPiece *P);
template uint8_t elf::getFdeEncoding<ELF32BE>(EhSectionPiece *P);
diff --git a/ELF/EhFrame.h b/ELF/EhFrame.h
index cadc93d3a2e4..4e2b6f83a294 100644
--- a/ELF/EhFrame.h
+++ b/ELF/EhFrame.h
@@ -14,11 +14,10 @@
namespace lld {
namespace elf {
-template <class ELFT> class InputSectionBase;
+class InputSectionBase;
struct EhSectionPiece;
-template <class ELFT>
-size_t readEhRecordSize(InputSectionBase<ELFT> *S, size_t Off);
+template <class ELFT> size_t readEhRecordSize(InputSectionBase *S, size_t Off);
template <class ELFT> uint8_t getFdeEncoding(EhSectionPiece *P);
}
}
diff --git a/ELF/Error.cpp b/ELF/Error.cpp
index d9b41f9c599e..2c61b58dfed5 100644
--- a/ELF/Error.cpp
+++ b/ELF/Error.cpp
@@ -20,10 +20,10 @@
#include <unistd.h>
#endif
-using namespace lld::elf;
using namespace llvm;
-namespace lld {
+using namespace lld;
+using namespace lld::elf;
uint64_t elf::ErrorCount;
raw_ostream *elf::ErrorOS;
@@ -33,6 +33,18 @@ StringRef elf::Argv0;
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
+// Prints "\n" or does nothing, depending on Msg contents of
+// the previous call of this function.
+static void newline(const Twine &Msg) {
+ // True if the previous error message contained "\n".
+ // We want to separate multi-line error messages with a newline.
+ static bool Flag;
+
+ if (Flag)
+ *ErrorOS << "\n";
+ Flag = (StringRef(Msg.str()).find('\n') != StringRef::npos);
+}
+
static void print(StringRef S, raw_ostream::Colors C) {
*ErrorOS << Argv0 + ": ";
if (Config->ColorDiagnostics) {
@@ -45,9 +57,16 @@ static void print(StringRef S, raw_ostream::Colors C) {
}
void elf::log(const Twine &Msg) {
- std::lock_guard<std::mutex> Lock(Mu);
- if (Config->Verbose)
+ if (Config->Verbose) {
+ std::lock_guard<std::mutex> Lock(Mu);
outs() << Argv0 << ": " << Msg << "\n";
+ }
+}
+
+void elf::message(const Twine &Msg) {
+ std::lock_guard<std::mutex> Lock(Mu);
+ outs() << Msg << "\n";
+ outs().flush();
}
void elf::warn(const Twine &Msg) {
@@ -55,13 +74,16 @@ void elf::warn(const Twine &Msg) {
error(Msg);
return;
}
+
std::lock_guard<std::mutex> Lock(Mu);
+ newline(Msg);
print("warning: ", raw_ostream::MAGENTA);
*ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
+ newline(Msg);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
print("error: ", raw_ostream::RED);
@@ -77,10 +99,6 @@ void elf::error(const Twine &Msg) {
++ErrorCount;
}
-void elf::error(std::error_code EC, const Twine &Prefix) {
- error(Prefix + ": " + EC.message());
-}
-
void elf::exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
@@ -93,18 +111,6 @@ void elf::exitLld(int Val) {
}
void elf::fatal(const Twine &Msg) {
- std::lock_guard<std::mutex> Lock(Mu);
- print("error: ", raw_ostream::RED);
- *ErrorOS << Msg << "\n";
+ error(Msg);
exitLld(1);
}
-
-void elf::fatal(std::error_code EC, const Twine &Prefix) {
- fatal(Prefix + ": " + EC.message());
-}
-
-void elf::fatal(Error &E, const Twine &Prefix) {
- fatal(Prefix + ": " + llvm::toString(std::move(E)));
-}
-
-} // namespace lld
diff --git a/ELF/Error.h b/ELF/Error.h
index f18cf456da6d..dd6e37c99b15 100644
--- a/ELF/Error.h
+++ b/ELF/Error.h
@@ -15,10 +15,14 @@
// Error prints out an error message and increment a global variable
// ErrorCount to record the fact that we met an error condition. It does
// not exit, so it is safe for a lld-as-a-library use case. It is generally
-// useful because it can report more than one errors in a single run.
+// useful because it can report more than one error in a single run.
//
// Warn doesn't do anything but printing out a given message.
//
+// It is not recommended to use llvm::outs() or llvm::errs() directly
+// in LLD because they are not thread-safe. The functions declared in
+// this file are mutually excluded, so you want to use them instead.
+//
//===----------------------------------------------------------------------===//
#ifndef LLD_ELF_ERROR_H
@@ -36,15 +40,12 @@ extern llvm::raw_ostream *ErrorOS;
extern llvm::StringRef Argv0;
void log(const Twine &Msg);
+void message(const Twine &Msg);
void warn(const Twine &Msg);
-
void error(const Twine &Msg);
-void error(std::error_code EC, const Twine &Prefix);
+LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
-LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
-LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
-LLVM_ATTRIBUTE_NORETURN void fatal(Error &E, const Twine &Prefix);
// check() functions are convenient functions to strip errors
// from error-or-value objects.
@@ -68,7 +69,7 @@ template <class T> T check(ErrorOr<T> E, const Twine &Prefix) {
template <class T> T check(Expected<T> E, const Twine &Prefix) {
if (!E)
- fatal(Prefix + ": " + errorToErrorCode(E.takeError()).message());
+ fatal(Prefix + ": " + toString(E.takeError()));
return std::move(*E);
}
diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp
new file mode 100644
index 000000000000..75f7bda75a23
--- /dev/null
+++ b/ELF/Filesystem.cpp
@@ -0,0 +1,79 @@
+//===- Filesystem.cpp -----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a few utility functions to handle files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Filesystem.h"
+#include "Config.h"
+#include "Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include <thread>
+
+using namespace llvm;
+
+using namespace lld;
+using namespace lld::elf;
+
+// Removes a given file asynchronously. This is a performance hack,
+// so remove this when operating systems are improved.
+//
+// On Linux (and probably on other Unix-like systems), unlink(2) is a
+// noticeably slow system call. As of 2016, unlink takes 250
+// milliseconds to remove a 1 GB file on ext4 filesystem on my machine.
+//
+// To create a new result file, we first remove existing file. So, if
+// you repeatedly link a 1 GB program in a regular compile-link-debug
+// cycle, every cycle wastes 250 milliseconds only to remove a file.
+// Since LLD can link a 1 GB binary in about 5 seconds, that waste
+// actually counts.
+//
+// This function spawns a background thread to call unlink.
+// The calling thread returns almost immediately.
+void elf::unlinkAsync(StringRef Path) {
+ if (!Config->Threads || !sys::fs::exists(Config->OutputFile))
+ return;
+
+ // First, rename Path to avoid race condition. We cannot remove
+ // Path from a different thread because we are now going to create
+ // Path as a new file. If we do that in a different thread, the new
+ // thread can remove the new file.
+ SmallString<128> TempPath;
+ if (sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath))
+ return;
+ if (sys::fs::rename(Path, TempPath)) {
+ sys::fs::remove(TempPath);
+ return;
+ }
+
+ // Remove TempPath in background.
+ std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach();
+}
+
+// Returns true if a given file seems to be writable.
+//
+// Determining whether a file is writable or not is amazingly hard,
+// and after all the only reliable way of doing that is to actually
+// create a file. But we don't want to do that in this function
+// because LLD shouldn't update any file if it will end in a failure.
+// We also don't want to reimplement heuristics. So we'll let
+// FileOutputBuffer do the work.
+//
+// FileOutputBuffer doesn't touch a desitnation file until commit()
+// is called. We use that class without calling commit() to predict
+// if the given file is writable.
+bool elf::isFileWritable(StringRef Path, StringRef Desc) {
+ if (auto EC = FileOutputBuffer::create(Path, 1).getError()) {
+ error("cannot open " + Desc + " " + Path + ": " + EC.message());
+ return false;
+ }
+ return true;
+}
diff --git a/ELF/Filesystem.h b/ELF/Filesystem.h
new file mode 100644
index 000000000000..a33dc3651a4a
--- /dev/null
+++ b/ELF/Filesystem.h
@@ -0,0 +1,22 @@
+//===- Filesystem.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_FILESYSTEM_H
+#define LLD_ELF_FILESYSTEM_H
+
+#include "lld/Core/LLVM.h"
+
+namespace lld {
+namespace elf {
+void unlinkAsync(StringRef Path);
+bool isFileWritable(StringRef Path, StringRef FileDescription);
+}
+}
+
+#endif
diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp
index 762144dd0a96..99e02d0025b0 100644
--- a/ELF/GdbIndex.cpp
+++ b/ELF/GdbIndex.cpp
@@ -7,199 +7,43 @@
//
//===----------------------------------------------------------------------===//
//
-// File contains classes for implementation of --gdb-index command line option.
+// The -gdb-index option instructs the linker to emit a .gdb_index section.
+// The section contains information to make gdb startup faster.
+// The format of the section is described at
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html.
//
-// If that option is used, linker should emit a .gdb_index section that allows
-// debugger to locate and read .dwo files, containing neccessary debug
-// information.
-// More information about implementation can be found in DWARF specification,
-// latest version is available at http://dwarfstd.org.
-//
-// .gdb_index section format:
-// (Information is based on/taken from
-// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html (*))
-//
-// A mapped index consists of several areas, laid out in order:
-// 1) The file header.
-// 2) "The CU (compilation unit) list. This is a sequence of pairs of 64-bit
-// little-endian values, sorted by the CU offset. The first element in each
-// pair is the offset of a CU in the .debug_info section. The second element
-// in each pair is the length of that CU. References to a CU elsewhere in the
-// map are done using a CU index, which is just the 0-based index into this
-// table. Note that if there are type CUs, then conceptually CUs and type CUs
-// form a single list for the purposes of CU indices."(*)
-// 3) The types CU list. Depricated as .debug_types does not appear in the DWARF
-// v5 specification.
-// 4) The address area. The address area is a sequence of address
-// entries, where each entrie contains low address, high address and CU
-// index.
-// 5) "The symbol table. This is an open-addressed hash table. The size of the
-// hash table is always a power of 2. Each slot in the hash table consists of
-// a pair of offset_type values. The first value is the offset of the
-// symbol's name in the constant pool. The second value is the offset of the
-// CU vector in the constant pool."(*)
-// 6) "The constant pool. This is simply a bunch of bytes. It is organized so
-// that alignment is correct: CU vectors are stored first, followed by
-// strings." (*)
-//
-// For constructing the .gdb_index section following steps should be performed:
-// 1) For file header nothing special should be done. It contains the offsets to
-// the areas below.
-// 2) Scan the compilation unit headers of the .debug_info sections to build a
-// list of compilation units.
-// 3) CU Types are no longer needed as DWARF skeleton type units never made it
-// into the standard. lld does nothing to support parsing of .debug_types
-// and generates empty types CU area in .gdb_index section.
-// 4) Address area entries are extracted from DW_TAG_compile_unit DIEs of
-// .debug_info sections.
-// 5) For building the symbol table linker extracts the public names from the
-// .debug_gnu_pubnames and .debug_gnu_pubtypes sections. Then it builds the
-// hashtable in according to .gdb_index format specification.
-// 6) Constant pool is populated at the same time as symbol table.
//===----------------------------------------------------------------------===//
#include "GdbIndex.h"
+#include "Memory.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
#include "llvm/Object/ELFObjectFile.h"
using namespace llvm;
using namespace llvm::object;
+using namespace lld;
using namespace lld::elf;
-template <class ELFT>
-GdbIndexBuilder<ELFT>::GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec)
- : DebugInfoSec(DebugInfoSec) {
- if (Expected<std::unique_ptr<object::ObjectFile>> Obj =
- object::ObjectFile::createObjectFile(DebugInfoSec->getFile()->MB))
- Dwarf.reset(new DWARFContextInMemory(*Obj.get(), this));
- else
- error(toString(DebugInfoSec->getFile()) + ": error creating DWARF context");
-}
-
-template <class ELFT>
-std::vector<std::pair<typename ELFT::uint, typename ELFT::uint>>
-GdbIndexBuilder<ELFT>::readCUList() {
- std::vector<std::pair<uintX_t, uintX_t>> Ret;
- for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units())
- Ret.push_back(
- {DebugInfoSec->OutSecOff + CU->getOffset(), CU->getLength() + 4});
- return Ret;
-}
-
-template <class ELFT>
-std::vector<std::pair<StringRef, uint8_t>>
-GdbIndexBuilder<ELFT>::readPubNamesAndTypes() {
- const bool IsLE = ELFT::TargetEndianness == llvm::support::little;
- StringRef Data[] = {Dwarf->getGnuPubNamesSection(),
- Dwarf->getGnuPubTypesSection()};
-
- std::vector<std::pair<StringRef, uint8_t>> Ret;
- for (StringRef D : Data) {
- DWARFDebugPubTable PubTable(D, IsLE, true);
- for (const DWARFDebugPubTable::Set &S : PubTable.getData())
- for (const DWARFDebugPubTable::Entry &E : S.Entries)
- Ret.push_back({E.Name, E.Descriptor.toBits()});
- }
- return Ret;
-}
-
std::pair<bool, GdbSymbol *> GdbHashTab::add(uint32_t Hash, size_t Offset) {
- if (Size * 4 / 3 >= Table.size())
- expand();
-
- GdbSymbol **Slot = findSlot(Hash, Offset);
- bool New = false;
- if (*Slot == nullptr) {
- ++Size;
- *Slot = new (Alloc) GdbSymbol(Hash, Offset);
- New = true;
+ GdbSymbol *&Sym = Map[Offset];
+ if (Sym)
+ return {false, Sym};
+ Sym = make<GdbSymbol>(Hash, Offset);
+ return {true, Sym};
+}
+
+void GdbHashTab::finalizeContents() {
+ uint32_t Size = std::max<uint32_t>(1024, NextPowerOf2(Map.size() * 4 / 3));
+ uint32_t Mask = Size - 1;
+ Table.resize(Size);
+
+ for (auto &P : Map) {
+ GdbSymbol *Sym = P.second;
+ uint32_t I = Sym->NameHash & Mask;
+ uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1;
+
+ while (Table[I])
+ I = (I + Step) & Mask;
+ Table[I] = Sym;
}
- return {New, *Slot};
-}
-
-void GdbHashTab::expand() {
- if (Table.empty()) {
- Table.resize(InitialSize);
- return;
- }
- std::vector<GdbSymbol *> NewTable(Table.size() * 2);
- NewTable.swap(Table);
-
- for (GdbSymbol *Sym : NewTable) {
- if (!Sym)
- continue;
- GdbSymbol **Slot = findSlot(Sym->NameHash, Sym->NameOffset);
- *Slot = Sym;
- }
-}
-
-// Methods finds a slot for symbol with given hash. The step size used to find
-// the next candidate slot when handling a hash collision is specified in
-// .gdb_index section format. The hash value for a table entry is computed by
-// applying an iterative hash function to the symbol's name.
-GdbSymbol **GdbHashTab::findSlot(uint32_t Hash, size_t Offset) {
- uint32_t Index = Hash & (Table.size() - 1);
- uint32_t Step = ((Hash * 17) & (Table.size() - 1)) | 1;
-
- for (;;) {
- GdbSymbol *S = Table[Index];
- if (!S || ((S->NameOffset == Offset) && (S->NameHash == Hash)))
- return &Table[Index];
- Index = (Index + Step) & (Table.size() - 1);
- }
-}
-
-template <class ELFT>
-static InputSectionBase<ELFT> *
-findSection(ArrayRef<InputSectionBase<ELFT> *> Arr, uint64_t Offset) {
- for (InputSectionBase<ELFT> *S : Arr)
- if (S && S != &InputSection<ELFT>::Discarded)
- if (Offset >= S->Offset && Offset < S->Offset + S->getSize())
- return S;
- return nullptr;
-}
-
-template <class ELFT>
-std::vector<AddressEntry<ELFT>>
-GdbIndexBuilder<ELFT>::readAddressArea(size_t CurrentCU) {
- std::vector<AddressEntry<ELFT>> Ret;
- for (const auto &CU : Dwarf->compile_units()) {
- DWARFAddressRangesVector Ranges;
- CU->collectAddressRanges(Ranges);
-
- ArrayRef<InputSectionBase<ELFT> *> Sections =
- DebugInfoSec->getFile()->getSections();
-
- for (std::pair<uint64_t, uint64_t> &R : Ranges)
- if (InputSectionBase<ELFT> *S = findSection(Sections, R.first))
- Ret.push_back(
- {S, R.first - S->Offset, R.second - S->Offset, CurrentCU});
- ++CurrentCU;
- }
- return Ret;
-}
-
-// We return file offset as load address for allocatable sections. That is
-// currently used for collecting address ranges in readAddressArea(). We are
-// able then to find section index that range belongs to.
-template <class ELFT>
-uint64_t GdbIndexBuilder<ELFT>::getSectionLoadAddress(
- const object::SectionRef &Sec) const {
- if (static_cast<const ELFSectionRef &>(Sec).getFlags() & ELF::SHF_ALLOC)
- return static_cast<const ELFSectionRef &>(Sec).getOffset();
- return 0;
-}
-
-template <class ELFT>
-std::unique_ptr<LoadedObjectInfo> GdbIndexBuilder<ELFT>::clone() const {
- return {};
-}
-
-namespace lld {
-namespace elf {
-template class GdbIndexBuilder<ELF32LE>;
-template class GdbIndexBuilder<ELF32BE>;
-template class GdbIndexBuilder<ELF64LE>;
-template class GdbIndexBuilder<ELF64BE>;
-}
}
diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h
index c761ea173a8d..a36b92714def 100644
--- a/ELF/GdbIndex.h
+++ b/ELF/GdbIndex.h
@@ -17,48 +17,16 @@
namespace lld {
namespace elf {
-template <class ELFT> class InputSection;
+class InputSection;
// Struct represents single entry of address area of gdb index.
-template <class ELFT> struct AddressEntry {
- InputSectionBase<ELFT> *Section;
+struct AddressEntry {
+ InputSectionBase *Section;
uint64_t LowAddress;
uint64_t HighAddress;
size_t CuIndex;
};
-// GdbIndexBuilder is a helper class used for extracting data required
-// for building .gdb_index section from objects.
-template <class ELFT> class GdbIndexBuilder : public llvm::LoadedObjectInfo {
- typedef typename ELFT::uint uintX_t;
-
- InputSection<ELFT> *DebugInfoSec;
-
- std::unique_ptr<llvm::DWARFContext> Dwarf;
-
-public:
- GdbIndexBuilder(InputSection<ELFT> *DebugInfoSec);
-
- // Extracts the compilation units. Each first element of pair is a offset of a
- // CU in the .debug_info section and second is the length of that CU.
- std::vector<std::pair<uintX_t, uintX_t>> readCUList();
-
- // Extracts the vector of address area entries. Accepts global index of last
- // parsed CU.
- std::vector<AddressEntry<ELFT>> readAddressArea(size_t CurrentCU);
-
- // Method extracts public names and types. It returns list of name and
- // gnu_pub* kind pairs.
- std::vector<std::pair<StringRef, uint8_t>> readPubNamesAndTypes();
-
-private:
- // Method returns section file offset as a load addres for DWARF parser. That
- // allows to find the target section index for address ranges.
- uint64_t
- getSectionLoadAddress(const llvm::object::SectionRef &Sec) const override;
- std::unique_ptr<llvm::LoadedObjectInfo> clone() const override;
-};
-
// Element of GdbHashTab hash table.
struct GdbSymbol {
GdbSymbol(uint32_t Hash, size_t Offset)
@@ -75,22 +43,13 @@ class GdbHashTab final {
public:
std::pair<bool, GdbSymbol *> add(uint32_t Hash, size_t Offset);
+ void finalizeContents();
size_t getCapacity() { return Table.size(); }
GdbSymbol *getSymbol(size_t I) { return Table[I]; }
private:
- void expand();
-
- GdbSymbol **findSlot(uint32_t Hash, size_t Offset);
-
- llvm::BumpPtrAllocator Alloc;
+ llvm::DenseMap<size_t, GdbSymbol *> Map;
std::vector<GdbSymbol *> Table;
-
- // Size keeps the amount of filled entries in Table.
- size_t Size = 0;
-
- // Initial size must be a power of 2.
- static const int32_t InitialSize = 1024;
};
} // namespace elf
diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp
index 32cd0f8a185c..dcf01ea80011 100644
--- a/ELF/ICF.cpp
+++ b/ELF/ICF.cpp
@@ -77,7 +77,6 @@
#include "Config.h"
#include "SymbolTable.h"
#include "Threads.h"
-
#include "llvm/ADT/Hashing.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
@@ -102,11 +101,11 @@ private:
bool constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB);
template <class RelTy>
- bool variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
- const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB);
+ bool variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB);
- bool equalsConstant(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
- bool equalsVariable(const InputSection<ELFT> *A, const InputSection<ELFT> *B);
+ bool equalsConstant(const InputSection *A, const InputSection *B);
+ bool equalsVariable(const InputSection *A, const InputSection *B);
size_t findBoundary(size_t Begin, size_t End);
@@ -115,7 +114,7 @@ private:
void forEachClass(std::function<void(size_t, size_t)> Fn);
- std::vector<InputSection<ELFT> *> Sections;
+ std::vector<InputSection *> Sections;
// We repeat the main loop while `Repeat` is true.
std::atomic<bool> Repeat;
@@ -154,17 +153,17 @@ private:
// Returns a hash value for S. Note that the information about
// relocation targets is not included in the hash value.
-template <class ELFT> static uint32_t getHash(InputSection<ELFT> *S) {
+template <class ELFT> static uint32_t getHash(InputSection *S) {
return hash_combine(S->Flags, S->getSize(), S->NumRelocations);
}
// Returns true if section S is subject of ICF.
-template <class ELFT> static bool isEligible(InputSection<ELFT> *S) {
+static bool isEligible(InputSection *S) {
// .init and .fini contains instructions that must be executed to
// initialize and finalize the process. They cannot and should not
// be merged.
- return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) &&
- S->Name != ".init" && S->Name != ".fini";
+ return S->Live && (S->Flags & SHF_ALLOC) && (S->Flags & SHF_EXECINSTR) &&
+ !(S->Flags & SHF_WRITE) && S->Name != ".init" && S->Name != ".fini";
}
// Split an equivalence class into smaller classes.
@@ -181,17 +180,17 @@ void ICF<ELFT>::segregate(size_t Begin, size_t End, bool Constant) {
while (Begin < End) {
// Divide [Begin, End) into two. Let Mid be the start index of the
// second group.
- auto Bound = std::stable_partition(
- Sections.begin() + Begin + 1, Sections.begin() + End,
- [&](InputSection<ELFT> *S) {
- if (Constant)
- return equalsConstant(Sections[Begin], S);
- return equalsVariable(Sections[Begin], S);
- });
+ auto Bound =
+ std::stable_partition(Sections.begin() + Begin + 1,
+ Sections.begin() + End, [&](InputSection *S) {
+ if (Constant)
+ return equalsConstant(Sections[Begin], S);
+ return equalsVariable(Sections[Begin], S);
+ });
size_t Mid = Bound - Sections.begin();
// Now we split [Begin, End) into [Begin, Mid) and [Mid, End) by
- // updating the sections in [Begin, End). We use Mid as an equivalence
+ // updating the sections in [Begin, Mid). We use Mid as an equivalence
// class ID because every group ends with a unique index.
for (size_t I = Begin; I < Mid; ++I)
Sections[I]->Class[Next] = Mid;
@@ -210,7 +209,7 @@ template <class RelTy>
bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
auto Eq = [](const RelTy &A, const RelTy &B) {
return A.r_offset == B.r_offset &&
- A.getType(Config->Mips64EL) == B.getType(Config->Mips64EL) &&
+ A.getType(Config->IsMips64EL) == B.getType(Config->IsMips64EL) &&
getAddend<ELFT>(A) == getAddend<ELFT>(B);
};
@@ -221,40 +220,43 @@ bool ICF<ELFT>::constantEq(ArrayRef<RelTy> RelsA, ArrayRef<RelTy> RelsB) {
// Compare "non-moving" part of two InputSections, namely everything
// except relocation targets.
template <class ELFT>
-bool ICF<ELFT>::equalsConstant(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
+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)
return false;
if (A->AreRelocsRela)
- return constantEq(A->relas(), B->relas());
- return constantEq(A->rels(), B->rels());
+ return constantEq(A->template relas<ELFT>(), B->template relas<ELFT>());
+ return constantEq(A->template rels<ELFT>(), B->template rels<ELFT>());
}
// Compare two lists of relocations. Returns true if all pairs of
// relocations point to the same section in terms of ICF.
template <class ELFT>
template <class RelTy>
-bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
- const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB) {
+bool ICF<ELFT>::variableEq(const InputSection *A, ArrayRef<RelTy> RelsA,
+ const InputSection *B, ArrayRef<RelTy> RelsB) {
auto Eq = [&](const RelTy &RA, const RelTy &RB) {
// The two sections must be identical.
- SymbolBody &SA = A->getFile()->getRelocTargetSym(RA);
- SymbolBody &SB = B->getFile()->getRelocTargetSym(RB);
+ SymbolBody &SA = A->template getFile<ELFT>()->getRelocTargetSym(RA);
+ SymbolBody &SB = B->template getFile<ELFT>()->getRelocTargetSym(RB);
if (&SA == &SB)
return true;
- // Or, the two sections must be in the same equivalence class.
- auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
- auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
+ auto *DA = dyn_cast<DefinedRegular>(&SA);
+ auto *DB = dyn_cast<DefinedRegular>(&SB);
if (!DA || !DB)
return false;
if (DA->Value != DB->Value)
return false;
- auto *X = dyn_cast<InputSection<ELFT>>(DA->Section);
- auto *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
+ // Either both symbols must be absolute...
+ if (!DA->Section || !DB->Section)
+ return !DA->Section && !DB->Section;
+
+ // Or the two sections must be in the same equivalence class.
+ auto *X = dyn_cast<InputSection>(DA->Section);
+ auto *Y = dyn_cast<InputSection>(DB->Section);
if (!X || !Y)
return false;
@@ -271,11 +273,11 @@ bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
// Compare "moving" part of two InputSections, namely relocation targets.
template <class ELFT>
-bool ICF<ELFT>::equalsVariable(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
+bool ICF<ELFT>::equalsVariable(const InputSection *A, const InputSection *B) {
if (A->AreRelocsRela)
- return variableEq(A, A->relas(), B, B->relas());
- return variableEq(A, A->rels(), B, B->rels());
+ return variableEq(A, A->template relas<ELFT>(), B,
+ B->template relas<ELFT>());
+ return variableEq(A, A->template rels<ELFT>(), B, B->template rels<ELFT>());
}
template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
@@ -291,7 +293,7 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) {
// groups of sections, grouped by the class.
//
// This function calls Fn on every group that starts within [Begin, End).
-// Note that a group must starts in that range but doesn't necessarily
+// Note that a group must start in that range but doesn't necessarily
// have to end before End.
template <class ELFT>
void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End,
@@ -323,8 +325,9 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// Split sections into 256 shards and call Fn in parallel.
size_t NumShards = 256;
size_t Step = Sections.size() / NumShards;
- forLoop(0, NumShards,
- [&](size_t I) { forEachClassRange(I * Step, (I + 1) * Step, Fn); });
+ parallelFor(0, NumShards, [&](size_t I) {
+ forEachClassRange(I * Step, (I + 1) * Step, Fn);
+ });
forEachClassRange(Step * NumShards, Sections.size(), Fn);
++Cnt;
}
@@ -332,20 +335,20 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {
// The main function of ICF.
template <class ELFT> void ICF<ELFT>::run() {
// Collect sections to merge.
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections)
- if (auto *S = dyn_cast<InputSection<ELFT>>(Sec))
+ for (InputSectionBase *Sec : InputSections)
+ if (auto *S = dyn_cast<InputSection>(Sec))
if (isEligible(S))
Sections.push_back(S);
// Initially, we use hash values to partition sections.
- for (InputSection<ELFT> *S : Sections)
+ for (InputSection *S : Sections)
// Set MSB to 1 to avoid collisions with non-hash IDs.
- S->Class[0] = getHash(S) | (1 << 31);
+ S->Class[0] = getHash<ELFT>(S) | (1 << 31);
// From now on, sections in Sections vector are ordered so that sections
// in the same equivalence class are consecutive in the vector.
std::stable_sort(Sections.begin(), Sections.end(),
- [](InputSection<ELFT> *A, InputSection<ELFT> *B) {
+ [](InputSection *A, InputSection *B) {
return A->Class[0] < B->Class[0];
});
@@ -372,6 +375,15 @@ template <class ELFT> void ICF<ELFT>::run() {
Sections[Begin]->replace(Sections[I]);
}
});
+
+ // Mark ARM Exception Index table sections that refer to folded code
+ // sections as not live. These sections have an implict dependency
+ // via the link order dependency.
+ if (Config->EMachine == EM_ARM)
+ for (InputSectionBase *Sec : InputSections)
+ if (auto *S = dyn_cast<InputSection>(Sec))
+ if (S->Flags & SHF_LINK_ORDER)
+ S->Live = S->getLinkOrderDep()->Live;
}
// ICF entry point function.
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index f3afb1c34562..d651fbcad253 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -16,7 +16,6 @@
#include "Symbols.h"
#include "SyntheticSections.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/IR/LLVMContext.h"
@@ -38,6 +37,8 @@ using namespace lld::elf;
TarWriter *elf::Tar;
+InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+
namespace {
// In ELF object file all section addresses are zero. If we have multiple
// .text sections (when using -ffunction-section or comdat group) then
@@ -56,14 +57,13 @@ public:
}
Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
- if (Config->Verbose)
- outs() << Path << "\n";
-
+ log(Path);
auto MBOrErr = MemoryBuffer::getFile(Path);
if (auto EC = MBOrErr.getError()) {
- error(EC, "cannot open " + Path);
+ error("cannot open " + Path + ": " + EC.message());
return None;
}
+
std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
MemoryBufferRef MBRef = MB->getMemBufferRef();
make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
@@ -75,15 +75,13 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) {
template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
std::unique_ptr<object::ObjectFile> Obj =
- check(object::ObjectFile::createObjectFile(this->MB),
- "createObjectFile failed");
+ check(object::ObjectFile::createObjectFile(this->MB), toString(this));
ObjectInfo ObjInfo;
DWARFContextInMemory Dwarf(*Obj, &ObjInfo);
DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs));
- DataExtractor LineData(Dwarf.getLineSection().Data,
- ELFT::TargetEndianness == support::little,
- ELFT::Is64Bits ? 8 : 4);
+ DataExtractor LineData(Dwarf.getLineSection().Data, Config->IsLE,
+ Config->Wordsize);
// The second parameter is offset in .debug_line section
// for compilation unit (CU) of interest. We have only one
@@ -94,34 +92,49 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() {
// Returns source line information for a given offset
// using DWARF debug info.
template <class ELFT>
-std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase<ELFT> *S,
- uintX_t Offset) {
+Optional<DILineInfo> elf::ObjectFile<ELFT>::getDILineInfo(InputSectionBase *S,
+ uint64_t Offset) {
if (!DwarfLine)
initializeDwarfLine();
// The offset to CU is 0.
const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0);
if (!Tbl)
- return "";
+ return None;
// Use fake address calcuated by adding section file offset and offset in
// section. See comments for ObjectInfo class.
DILineInfo Info;
Tbl->getFileLineInfoForAddress(
- S->Offset + Offset, nullptr,
+ S->getOffsetInFile() + Offset, nullptr,
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info);
if (Info.Line == 0)
- return "";
- return Info.FileName + ":" + std::to_string(Info.Line);
+ return None;
+ return Info;
+}
+
+// Returns source line information for a given offset
+// using DWARF debug info.
+template <class ELFT>
+std::string elf::ObjectFile<ELFT>::getLineInfo(InputSectionBase *S,
+ uint64_t Offset) {
+ if (Optional<DILineInfo> Info = getDILineInfo(S, Offset))
+ return Info->FileName + ":" + std::to_string(Info->Line);
+ return "";
}
// Returns "(internal)", "foo.a(bar.o)" or "baz.o".
std::string lld::toString(const InputFile *F) {
if (!F)
return "(internal)";
- if (!F->ArchiveName.empty())
- return (F->ArchiveName + "(" + F->getName() + ")").str();
- return F->getName();
+
+ if (F->ToStringCache.empty()) {
+ if (F->ArchiveName.empty())
+ F->ToStringCache = F->getName();
+ else
+ F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str();
+ }
+ return F->ToStringCache;
}
template <class ELFT> static ELFKind getELFKind() {
@@ -144,18 +157,20 @@ typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalSymbols() {
template <class ELFT>
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
- return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX));
+ return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX),
+ toString(this));
}
template <class ELFT>
void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr *Symtab) {
FirstNonLocal = Symtab->sh_info;
- Symbols = check(getObj().symbols(Symtab));
+ Symbols = check(getObj().symbols(Symtab), toString(this));
if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size())
fatal(toString(this) + ": invalid sh_info in symbol table");
- StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections));
+ StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections),
+ toString(this));
}
template <class ELFT>
@@ -163,11 +178,6 @@ elf::ObjectFile<ELFT>::ObjectFile(MemoryBufferRef M)
: ELFFileBase<ELFT>(Base::ObjectKind, M) {}
template <class ELFT>
-ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getNonLocalSymbols() {
- return makeArrayRef(this->SymbolBodies).slice(this->FirstNonLocal);
-}
-
-template <class ELFT>
ArrayRef<SymbolBody *> elf::ObjectFile<ELFT>::getLocalSymbols() {
if (this->SymbolBodies.empty())
return this->SymbolBodies;
@@ -196,19 +206,20 @@ StringRef
elf::ObjectFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec) {
if (this->Symbols.empty())
- this->initSymtab(Sections,
- check(object::getSection<ELFT>(Sections, Sec.sh_link)));
- const Elf_Sym *Sym =
- check(object::getSymbol<ELFT>(this->Symbols, Sec.sh_info));
- return check(Sym->getName(this->StringTable));
+ this->initSymtab(
+ Sections,
+ check(object::getSection<ELFT>(Sections, Sec.sh_link), toString(this)));
+ const Elf_Sym *Sym = check(
+ object::getSymbol<ELFT>(this->Symbols, Sec.sh_info), toString(this));
+ return check(Sym->getName(this->StringTable), toString(this));
}
template <class ELFT>
ArrayRef<typename elf::ObjectFile<ELFT>::Elf_Word>
elf::ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
const ELFFile<ELFT> &Obj = this->getObj();
- ArrayRef<Elf_Word> Entries =
- check(Obj.template getSectionContentsAsArray<Elf_Word>(&Sec));
+ ArrayRef<Elf_Word> Entries = check(
+ Obj.template getSectionContentsAsArray<Elf_Word>(&Sec), toString(this));
if (Entries.empty() || Entries[0] != GRP_COMDAT)
fatal(toString(this) + ": unsupported SHT_GROUP format");
return Entries.slice(1);
@@ -242,14 +253,14 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
// the section does not hold a table of fixed-size entries". We know
// that Rust 1.13 produces a string mergeable section with a zero
// sh_entsize. Here we just accept it rather than being picky about it.
- uintX_t EntSize = Sec.sh_entsize;
+ uint64_t EntSize = Sec.sh_entsize;
if (EntSize == 0)
return false;
if (Sec.sh_size % EntSize)
fatal(toString(this) +
": SHF_MERGE section size must be a multiple of sh_entsize");
- uintX_t Flags = Sec.sh_flags;
+ uint64_t Flags = Sec.sh_flags;
if (!(Flags & SHF_MERGE))
return false;
if (Flags & SHF_WRITE)
@@ -270,76 +281,79 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {
template <class ELFT>
void elf::ObjectFile<ELFT>::initializeSections(
DenseSet<CachedHashStringRef> &ComdatGroups) {
- ArrayRef<Elf_Shdr> ObjSections = check(this->getObj().sections());
+ ArrayRef<Elf_Shdr> ObjSections =
+ check(this->getObj().sections(), toString(this));
const ELFFile<ELFT> &Obj = this->getObj();
uint64_t Size = ObjSections.size();
- Sections.resize(Size);
+ this->Sections.resize(Size);
unsigned I = -1;
- StringRef SectionStringTable = check(Obj.getSectionStringTable(ObjSections));
+ StringRef SectionStringTable =
+ check(Obj.getSectionStringTable(ObjSections), toString(this));
for (const Elf_Shdr &Sec : ObjSections) {
++I;
- if (Sections[I] == &InputSection<ELFT>::Discarded)
+ if (this->Sections[I] == &InputSection::Discarded)
continue;
// 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.
if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) {
- Sections[I] = &InputSection<ELFT>::Discarded;
+ this->Sections[I] = &InputSection::Discarded;
continue;
}
switch (Sec.sh_type) {
case SHT_GROUP:
- Sections[I] = &InputSection<ELFT>::Discarded;
- if (ComdatGroups.insert(CachedHashStringRef(
- getShtGroupSignature(ObjSections, Sec)))
+ this->Sections[I] = &InputSection::Discarded;
+ if (ComdatGroups
+ .insert(
+ CachedHashStringRef(getShtGroupSignature(ObjSections, Sec)))
.second)
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
- fatal(toString(this) + ": invalid section index in group: " +
- Twine(SecIndex));
- Sections[SecIndex] = &InputSection<ELFT>::Discarded;
+ fatal(toString(this) +
+ ": invalid section index in group: " + Twine(SecIndex));
+ this->Sections[SecIndex] = &InputSection::Discarded;
}
break;
case SHT_SYMTAB:
this->initSymtab(ObjSections, &Sec);
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections));
+ this->SymtabSHNDX =
+ check(Obj.getSHNDXTable(Sec, ObjSections), toString(this));
break;
case SHT_STRTAB:
case SHT_NULL:
break;
default:
- Sections[I] = createInputSection(Sec, SectionStringTable);
+ this->Sections[I] = createInputSection(Sec, SectionStringTable);
}
// .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 >= Sections.size())
+ if (Sec.sh_link >= this->Sections.size())
fatal(toString(this) + ": invalid sh_link index: " +
Twine(Sec.sh_link));
- auto *IS = cast<InputSection<ELFT>>(Sections[Sec.sh_link]);
- IS->DependentSection = Sections[I];
+ this->Sections[Sec.sh_link]->DependentSections.push_back(
+ this->Sections[I]);
}
}
}
template <class ELFT>
-InputSectionBase<ELFT> *
-elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
+InputSectionBase *elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
uint32_t Idx = Sec.sh_info;
- if (Idx >= Sections.size())
+ if (Idx >= this->Sections.size())
fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx));
- InputSectionBase<ELFT> *Target = Sections[Idx];
+ InputSectionBase *Target = this->Sections[Idx];
// Strictly speaking, a relocation section must be included in the
// group of the section it relocates. However, LLVM 3.3 and earlier
// would fail to do so, so we gracefully handle that case.
- if (Target == &InputSection<ELFT>::Discarded)
+ if (Target == &InputSection::Discarded)
return nullptr;
if (!Target)
@@ -348,11 +362,11 @@ elf::ObjectFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) {
}
template <class ELFT>
-InputSectionBase<ELFT> *
+InputSectionBase *
elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
StringRef SectionStringTable) {
- StringRef Name =
- check(this->getObj().getSectionName(&Sec, SectionStringTable));
+ StringRef Name = check(
+ this->getObj().getSectionName(&Sec, SectionStringTable), toString(this));
switch (Sec.sh_type) {
case SHT_ARM_ATTRIBUTES:
@@ -361,62 +375,91 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// attribute section for dlopen to work.
// In a full implementation we would merge all attribute sections.
if (In<ELFT>::ARMAttributes == nullptr) {
- In<ELFT>::ARMAttributes = make<InputSection<ELFT>>(this, &Sec, Name);
+ In<ELFT>::ARMAttributes = make<InputSection>(this, &Sec, Name);
return In<ELFT>::ARMAttributes;
}
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
case SHT_RELA:
case SHT_REL: {
+ // Find the relocation target section and associate this
+ // section with it. Target can be discarded, for example
+ // if it is a duplicated member of SHT_GROUP section, we
+ // do not create or proccess relocatable sections then.
+ InputSectionBase *Target = getRelocTarget(Sec);
+ if (!Target)
+ return nullptr;
+
// 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<ELFT>>(this, &Sec, Name);
+ return make<InputSection>(this, &Sec, Name);
- // Find the relocation target section and associate this
- // section with it.
- InputSectionBase<ELFT> *Target = getRelocTarget(Sec);
- if (!Target)
- return nullptr;
if (Target->FirstRelocation)
fatal(toString(this) +
": multiple relocation sections to one section are not supported");
- if (!isa<InputSection<ELFT>>(Target) && !isa<EhInputSection<ELFT>>(Target))
+ if (isa<MergeInputSection>(Target))
fatal(toString(this) +
": relocations pointing to SHF_MERGE are not supported");
size_t NumRelocations;
if (Sec.sh_type == SHT_RELA) {
- ArrayRef<Elf_Rela> Rels = check(this->getObj().relas(&Sec));
+ ArrayRef<Elf_Rela> Rels =
+ check(this->getObj().relas(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = true;
} else {
- ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec));
+ ArrayRef<Elf_Rel> Rels = check(this->getObj().rels(&Sec), toString(this));
Target->FirstRelocation = Rels.begin();
NumRelocations = Rels.size();
Target->AreRelocsRela = false;
}
assert(isUInt<31>(NumRelocations));
Target->NumRelocations = NumRelocations;
+
+ // Relocation sections processed by the linker are usually removed
+ // from the output, so returning `nullptr` for the normal case.
+ // However, if -emit-relocs is given, we need to leave them in the output.
+ // (Some post link analysis tools need this information.)
+ if (Config->EmitRelocs) {
+ InputSection *RelocSec = make<InputSection>(this, &Sec, Name);
+ // We will not emit relocation section if target was discarded.
+ Target->DependentSections.push_back(RelocSec);
+ return RelocSec;
+ }
return nullptr;
}
}
- // .note.GNU-stack is a marker section to control the presence of
- // PT_GNU_STACK segment in outputs. Since the presence of the segment
- // is controlled only by the command line option (-z execstack) in LLD,
- // .note.GNU-stack is ignored.
+ // The GNU linker uses .note.GNU-stack section as a marker indicating
+ // that the code in the object file does not expect that the stack is
+ // executable (in terms of NX bit). If all input files have the marker,
+ // the GNU linker adds a PT_GNU_STACK segment to tells the loader to
+ // make the stack non-executable. Most object files have this section as
+ // of 2017.
+ //
+ // But making the stack non-executable is a norm today for security
+ // reasons. Failure to do so may result in a serious security issue.
+ // Therefore, we make LLD always add PT_GNU_STACK unless it is
+ // explicitly told to do otherwise (by -z execstack). Because the stack
+ // executable-ness is controlled solely by command line options,
+ // .note.GNU-stack sections are simply ignored.
if (Name == ".note.GNU-stack")
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
+ // Split stacks is a feature to support a discontiguous stack. At least
+ // as of 2017, it seems that the feature is not being used widely.
+ // Only GNU gold supports that. We don't. For the details about that,
+ // see https://gcc.gnu.org/wiki/SplitStacks
if (Name == ".note.GNU-split-stack") {
- error("objects using splitstacks are not supported");
- return &InputSection<ELFT>::Discarded;
+ error(toString(this) +
+ ": object file compiled with -fsplit-stack is not supported");
+ return &InputSection::Discarded;
}
if (Config->Strip != StripPolicy::None && Name.startswith(".debug"))
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
// The linkonce feature is a sort of proto-comdat. Some glibc i386 object
// files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce
@@ -424,17 +467,17 @@ elf::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec,
// FIXME: This is glibc PR20543, we should remove this hack once that has been
// fixed for a while.
if (Name.startswith(".gnu.linkonce."))
- return &InputSection<ELFT>::Discarded;
+ return &InputSection::Discarded;
// The linker merges EH (exception handling) frames and creates a
// .eh_frame_hdr section for runtime. So we handle them with a special
// class. For relocatable outputs, they are just passed through.
if (Name == ".eh_frame" && !Config->Relocatable)
- return make<EhInputSection<ELFT>>(this, &Sec, Name);
+ return make<EhInputSection>(this, &Sec, Name);
if (shouldMerge(Sec))
- return make<MergeInputSection<ELFT>>(this, &Sec, Name);
- return make<InputSection<ELFT>>(this, &Sec, Name);
+ return make<MergeInputSection>(this, &Sec, Name);
+ return make<InputSection>(this, &Sec, Name);
}
template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
@@ -444,12 +487,11 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeSymbols() {
}
template <class ELFT>
-InputSectionBase<ELFT> *
-elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
+InputSectionBase *elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = this->getSectionIndex(Sym);
- if (Index >= Sections.size())
+ if (Index >= this->Sections.size())
fatal(toString(this) + ": invalid section index: " + Twine(Index));
- InputSectionBase<ELFT> *S = Sections[Index];
+ InputSectionBase *S = this->Sections[Index];
// We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could
// generate broken objects. STT_SECTION/STT_NOTYPE symbols can be
@@ -463,7 +505,7 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
fatal(toString(this) + ": invalid section index: " + Twine(Index));
}
- if (S == &InputSection<ELFT>::Discarded)
+ if (S == &InputSection::Discarded)
return S;
return S->Repl;
}
@@ -471,30 +513,29 @@ elf::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
template <class ELFT>
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
int Binding = Sym->getBinding();
- InputSectionBase<ELFT> *Sec = getSection(*Sym);
+ InputSectionBase *Sec = getSection(*Sym);
uint8_t StOther = Sym->st_other;
uint8_t Type = Sym->getType();
- uintX_t Value = Sym->st_value;
- uintX_t Size = Sym->st_size;
+ uint64_t Value = Sym->st_value;
+ uint64_t Size = Sym->st_size;
if (Binding == STB_LOCAL) {
if (Sym->getType() == STT_FILE)
- SourceFile = check(Sym->getName(this->StringTable));
+ SourceFile = check(Sym->getName(this->StringTable), toString(this));
if (this->StringTable.size() <= Sym->st_name)
fatal(toString(this) + ": invalid symbol name offset");
StringRefZ Name = this->StringTable.data() + Sym->st_name;
if (Sym->st_shndx == SHN_UNDEF)
- return new (BAlloc)
- Undefined<ELFT>(Name, /*IsLocal=*/true, StOther, Type, this);
+ return make<Undefined>(Name, /*IsLocal=*/true, StOther, Type, this);
- return new (BAlloc) DefinedRegular<ELFT>(Name, /*IsLocal=*/true, StOther,
- Type, Value, Size, Sec, this);
+ return make<DefinedRegular>(Name, /*IsLocal=*/true, StOther, Type, Value,
+ Size, Sec, this);
}
- StringRef Name = check(Sym->getName(this->StringTable));
+ StringRef Name = check(Sym->getName(this->StringTable), toString(this));
switch (Sym->st_shndx) {
case SHN_UNDEF:
@@ -517,7 +558,7 @@ SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE:
- if (Sec == &InputSection<ELFT>::Discarded)
+ if (Sec == &InputSection::Discarded)
return elf::Symtab<ELFT>::X
->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type,
/*CanOmitFromDynSym=*/false, this)
@@ -533,27 +574,34 @@ template <class ELFT> void ArchiveFile::parse() {
MB.getBufferIdentifier() + ": failed to parse archive");
// Read the symbol table to construct Lazy objects.
- for (const Archive::Symbol &Sym : File->symbols())
+ for (const Archive::Symbol &Sym : File->symbols()) {
Symtab<ELFT>::X->addLazyArchive(this, Sym);
+ }
+
+ if (File->symbols().begin() == File->symbols().end())
+ Config->ArchiveWithoutSymbolsSeen = true;
}
// Returns a buffer pointing to a member file containing a given symbol.
std::pair<MemoryBufferRef, uint64_t>
ArchiveFile::getMember(const Archive::Symbol *Sym) {
Archive::Child C =
- check(Sym->getMember(),
- "could not get the member for symbol " + Sym->getName());
+ check(Sym->getMember(), toString(this) +
+ ": could not get the member for symbol " +
+ Sym->getName());
if (!Seen.insert(C.getChildOffset()).second)
return {MemoryBufferRef(), 0};
MemoryBufferRef Ret =
check(C.getMemoryBufferRef(),
- "could not get the buffer for the member defining symbol " +
+ toString(this) +
+ ": could not get the buffer for the member defining symbol " +
Sym->getName());
if (C.getParent()->isThin() && Tar)
- Tar->append(relativeToRoot(check(C.getFullName())), Ret.getBuffer());
+ Tar->append(relativeToRoot(check(C.getFullName(), toString(this))),
+ Ret.getBuffer());
if (C.getParent()->isThin())
return {Ret, 0};
return {Ret, C.getChildOffset()};
@@ -567,16 +615,24 @@ template <class ELFT>
const typename ELFT::Shdr *
SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
return check(
- this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX));
+ this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX),
+ toString(this));
+}
+
+template <class ELFT> StringRef SharedFile<ELFT>::getSoName() const {
+ if (SoName.empty())
+ return this->DefaultSoName;
+ return SoName;
}
// Partially parse the shared object file so that we can call
// getSoName on this object.
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
const Elf_Shdr *DynamicSec = nullptr;
-
const ELFFile<ELFT> Obj = this->getObj();
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
+
+ // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d.
for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
default:
@@ -588,7 +644,8 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
DynamicSec = &Sec;
break;
case SHT_SYMTAB_SHNDX:
- this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections));
+ this->SymtabSHNDX =
+ check(Obj.getSHNDXTable(Sec, Sections), toString(this));
break;
case SHT_GNU_versym:
this->VersymSec = &Sec;
@@ -602,20 +659,15 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
if (this->VersymSec && this->Symbols.empty())
error("SHT_GNU_versym should be associated with symbol table");
- // DSOs are identified by soname, and they usually contain
- // DT_SONAME tag in their header. But if they are missing,
- // filenames are used as default sonames.
- SoName = sys::path::filename(this->getName());
-
+ // Search for a DT_SONAME tag to initialize this->SoName.
if (!DynamicSec)
return;
-
ArrayRef<Elf_Dyn> Arr =
check(Obj.template getSectionContentsAsArray<Elf_Dyn>(DynamicSec),
- toString(this) + ": getSectionContentsAsArray failed");
+ toString(this));
for (const Elf_Dyn &Dyn : Arr) {
if (Dyn.d_tag == DT_SONAME) {
- uintX_t Val = Dyn.getVal();
+ uint64_t Val = Dyn.getVal();
if (Val >= this->StringTable.size())
fatal(toString(this) + ": invalid DT_SONAME entry");
SoName = StringRef(this->StringTable.data() + Val);
@@ -681,7 +733,7 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
bool Hidden = VersymIndex & VERSYM_HIDDEN;
VersymIndex = VersymIndex & ~VERSYM_HIDDEN;
- StringRef Name = check(Sym.getName(this->StringTable));
+ StringRef Name = check(Sym.getName(this->StringTable), toString(this));
if (Sym.isUndefined()) {
Undefs.push_back(Name);
continue;
@@ -707,19 +759,18 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() {
}
}
-static ELFKind getBitcodeELFKind(MemoryBufferRef MB) {
- Triple T(check(getBitcodeTargetTriple(MB)));
+static ELFKind getBitcodeELFKind(const Triple &T) {
if (T.isLittleEndian())
return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind;
return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind;
}
-static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
- Triple T(check(getBitcodeTargetTriple(MB)));
+static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) {
switch (T.getArch()) {
case Triple::aarch64:
return EM_AARCH64;
case Triple::arm:
+ case Triple::thumb:
return EM_ARM;
case Triple::mips:
case Triple::mipsel:
@@ -735,14 +786,32 @@ static uint8_t getBitcodeMachineKind(MemoryBufferRef MB) {
case Triple::x86_64:
return EM_X86_64;
default:
- fatal(MB.getBufferIdentifier() +
- ": could not infer e_machine from bitcode target triple " + T.str());
+ fatal(Path + ": could not infer e_machine from bitcode target triple " +
+ T.str());
}
}
-BitcodeFile::BitcodeFile(MemoryBufferRef MB) : InputFile(BitcodeKind, MB) {
- EKind = getBitcodeELFKind(MB);
- EMachine = getBitcodeMachineKind(MB);
+BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName,
+ uint64_t OffsetInArchive)
+ : InputFile(BitcodeKind, MB) {
+ this->ArchiveName = ArchiveName;
+
+ // Here we pass a new MemoryBufferRef which is identified by ArchiveName
+ // (the fully resolved path of the archive) + member name + offset of the
+ // member in the archive.
+ // ThinLTO uses the MemoryBufferRef identifier to access its internal
+ // data structures and if two archives define two members with the same name,
+ // this causes a collision which result in only one of the objects being
+ // taken into consideration at LTO time (which very likely causes undefined
+ // symbols later in the link stage).
+ MemoryBufferRef MBRef(MB.getBuffer(),
+ Saver.save(ArchiveName + MB.getBufferIdentifier() +
+ utostr(OffsetInArchive)));
+ Obj = check(lto::InputFile::create(MBRef), toString(this));
+
+ Triple T(Obj->getTargetTriple());
+ EKind = getBitcodeELFKind(T);
+ EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T);
}
static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) {
@@ -762,25 +831,24 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
const lto::InputFile::Symbol &ObjSym,
BitcodeFile *F) {
StringRef NameRef = Saver.save(ObjSym.getName());
- uint32_t Flags = ObjSym.getFlags();
- uint32_t Binding = (Flags & BasicSymbolRef::SF_Weak) ? STB_WEAK : STB_GLOBAL;
+ uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL;
uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE;
uint8_t Visibility = mapVisibility(ObjSym.getVisibility());
bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable();
- int C = check(ObjSym.getComdatIndex());
+ int C = ObjSym.getComdatIndex();
if (C != -1 && !KeptComdats[C])
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
- if (Flags & BasicSymbolRef::SF_Undefined)
+ if (ObjSym.isUndefined())
return Symtab<ELFT>::X->addUndefined(NameRef, /*IsLocal=*/false, Binding,
Visibility, Type, CanOmitFromDynSym,
F);
- if (Flags & BasicSymbolRef::SF_Common)
+ if (ObjSym.isCommon())
return Symtab<ELFT>::X->addCommon(NameRef, ObjSym.getCommonSize(),
ObjSym.getCommonAlignment(), Binding,
Visibility, STT_OBJECT, F);
@@ -791,24 +859,9 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats,
template <class ELFT>
void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) {
-
- // Here we pass a new MemoryBufferRef which is identified by ArchiveName
- // (the fully resolved path of the archive) + member name + offset of the
- // member in the archive.
- // ThinLTO uses the MemoryBufferRef identifier to access its internal
- // data structures and if two archives define two members with the same name,
- // this causes a collision which result in only one of the objects being
- // taken into consideration at LTO time (which very likely causes undefined
- // symbols later in the link stage).
- Obj = check(lto::InputFile::create(MemoryBufferRef(
- MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() +
- utostr(OffsetInArchive)))));
-
std::vector<bool> KeptComdats;
- for (StringRef S : Obj->getComdatTable()) {
- StringRef N = Saver.save(S);
- KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(N)).second);
- }
+ for (StringRef S : Obj->getComdatTable())
+ KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second);
for (const lto::InputFile::Symbol &ObjSym : Obj->symbols())
Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this));
@@ -857,8 +910,8 @@ template <class ELFT> void BinaryFile::parse() {
StringRef EndName = Saver.save(Twine(Filename) + "_end");
StringRef SizeName = Saver.save(Twine(Filename) + "_size");
- auto *Section = make<InputSection<ELFT>>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
- 8, Data, ".data");
+ auto *Section =
+ make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data");
Sections.push_back(Section);
elf::Symtab<ELFT>::X->addRegular(StartName, STV_DEFAULT, STT_OBJECT, 0, 0,
@@ -878,10 +931,10 @@ static bool isBitcode(MemoryBufferRef MB) {
InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName,
uint64_t OffsetInArchive) {
- InputFile *F =
- isBitcode(MB) ? make<BitcodeFile>(MB) : createELFFile<ObjectFile>(MB);
+ InputFile *F = isBitcode(MB)
+ ? make<BitcodeFile>(MB, ArchiveName, OffsetInArchive)
+ : createELFFile<ObjectFile>(MB);
F->ArchiveName = ArchiveName;
- F->OffsetInArchive = OffsetInArchive;
return F;
}
@@ -907,27 +960,31 @@ template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
typedef typename ELFT::SymRange Elf_Sym_Range;
const ELFFile<ELFT> Obj(this->MB.getBuffer());
- ArrayRef<Elf_Shdr> Sections = check(Obj.sections());
+ ArrayRef<Elf_Shdr> Sections = check(Obj.sections(), toString(this));
for (const Elf_Shdr &Sec : Sections) {
if (Sec.sh_type != SHT_SYMTAB)
continue;
- Elf_Sym_Range Syms = check(Obj.symbols(&Sec));
+
+ Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this));
uint32_t FirstNonLocal = Sec.sh_info;
- StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections));
+ StringRef StringTable =
+ check(Obj.getStringTableForSymtab(Sec, Sections), toString(this));
std::vector<StringRef> V;
+
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
if (Sym.st_shndx != SHN_UNDEF)
- V.push_back(check(Sym.getName(StringTable)));
+ V.push_back(check(Sym.getName(StringTable), toString(this)));
return V;
}
return {};
}
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
- std::unique_ptr<lto::InputFile> Obj = check(lto::InputFile::create(this->MB));
+ std::unique_ptr<lto::InputFile> Obj =
+ check(lto::InputFile::create(this->MB), toString(this));
std::vector<StringRef> V;
for (const lto::InputFile::Symbol &Sym : Obj->symbols())
- if (!(Sym.getFlags() & BasicSymbolRef::SF_Undefined))
+ if (!Sym.isUndefined())
V.push_back(Saver.save(Sym.getName()));
return V;
}
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 95888061d877..40a8b23c5ef4 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -30,6 +30,7 @@
namespace llvm {
class DWARFDebugLine;
class TarWriter;
+struct DILineInfo;
namespace lto {
class InputFile;
}
@@ -74,25 +75,34 @@ public:
StringRef getName() const { return MB.getBufferIdentifier(); }
MemoryBufferRef MB;
+ // Returns sections. It is a runtime error to call this function
+ // on files that don't have the notion of sections.
+ ArrayRef<InputSectionBase *> getSections() const {
+ assert(FileKind == ObjectKind || FileKind == BinaryKind);
+ return Sections;
+ }
+
// Filename of .a which contained this file. If this file was
// not in an archive file, it is the empty string. We use this
// string for creating error messages.
StringRef ArchiveName;
- // If this file is in an archive, the member contains the offset of
- // the file in the archive. Otherwise, it's just zero. We store this
- // field so that we can pass it to lib/LTO in order to disambiguate
- // between objects.
- uint64_t OffsetInArchive;
-
// If this is an architecture-specific file, the following members
// have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type.
ELFKind EKind = ELFNoneKind;
uint16_t EMachine = llvm::ELF::EM_NONE;
uint8_t OSABI = 0;
+ // For SharedKind inputs, the string to use in DT_NEEDED when the library
+ // has no soname.
+ std::string DefaultSoName;
+
+ // Cache for toString(). Only toString() should use this member.
+ mutable std::string ToStringCache;
+
protected:
- InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+ InputFile(Kind K, MemoryBufferRef M);
+ std::vector<InputSectionBase *> Sections;
private:
const Kind FileKind;
@@ -136,9 +146,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef typename ELFT::Rela Elf_Rela;
typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
StringRef getShtGroupSignature(ArrayRef<Elf_Shdr> Sections,
const Elf_Shdr &Sec);
@@ -151,13 +159,11 @@ public:
ArrayRef<SymbolBody *> getSymbols();
ArrayRef<SymbolBody *> getLocalSymbols();
- ArrayRef<SymbolBody *> getNonLocalSymbols();
explicit ObjectFile(MemoryBufferRef M);
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
- ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
- InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
+ InputSectionBase *getSection(const Elf_Sym &Sym) const;
SymbolBody &getSymbolBody(uint32_t SymbolIndex) const {
if (SymbolIndex >= SymbolBodies.size())
@@ -167,13 +173,14 @@ public:
template <typename RelT>
SymbolBody &getRelocTargetSym(const RelT &Rel) const {
- uint32_t SymIndex = Rel.getSymbol(Config->Mips64EL);
+ uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL);
return getSymbolBody(SymIndex);
}
// Returns source line information for a given offset.
// If no information is available, returns "".
- std::string getLineInfo(InputSectionBase<ELFT> *S, uintX_t Offset);
+ std::string getLineInfo(InputSectionBase *S, uint64_t Offset);
+ llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t);
// MIPS GP0 value defined by this file. This value represents the gp value
// used to create the relocatable object and required to support
@@ -190,16 +197,13 @@ private:
initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
void initializeSymbols();
void initializeDwarfLine();
- InputSectionBase<ELFT> *getRelocTarget(const Elf_Shdr &Sec);
- InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec,
- StringRef SectionStringTable);
+ InputSectionBase *getRelocTarget(const Elf_Shdr &Sec);
+ InputSectionBase *createInputSection(const Elf_Shdr &Sec,
+ StringRef SectionStringTable);
bool shouldMerge(const Elf_Shdr &Sec);
SymbolBody *createSymbolBody(const Elf_Sym *Sym);
- // List of all sections defined by this file.
- std::vector<InputSectionBase<ELFT> *> Sections;
-
// List of all symbols referenced or defined by this file.
std::vector<SymbolBody *> SymbolBodies;
@@ -256,7 +260,8 @@ private:
class BitcodeFile : public InputFile {
public:
- explicit BitcodeFile(MemoryBufferRef M);
+ BitcodeFile(MemoryBufferRef M, StringRef ArchiveName,
+ uint64_t OffsetInArchive);
static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; }
template <class ELFT>
void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups);
@@ -276,8 +281,6 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
typedef typename ELFT::SymRange Elf_Sym_Range;
typedef typename ELFT::Verdef Elf_Verdef;
typedef typename ELFT::Versym Elf_Versym;
- typedef typename ELFT::Word Elf_Word;
- typedef typename ELFT::uint uintX_t;
std::vector<StringRef> Undefs;
StringRef SoName;
@@ -285,7 +288,7 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
const Elf_Shdr *VerdefSec = nullptr;
public:
- StringRef getSoName() const { return SoName; }
+ StringRef getSoName() const;
const Elf_Shdr *getSection(const Elf_Sym &Sym) const;
llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; }
@@ -322,10 +325,6 @@ public:
explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {}
static bool classof(const InputFile *F) { return F->kind() == BinaryKind; }
template <class ELFT> void parse();
- ArrayRef<InputSectionData *> getSections() const { return Sections; }
-
-private:
- std::vector<InputSectionData *> Sections;
};
InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "",
diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp
index 6b1e92891b98..aff57551a8b3 100644
--- a/ELF/InputSection.cpp
+++ b/ELF/InputSection.cpp
@@ -22,6 +22,7 @@
#include "llvm/Object/Decompressor.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/Path.h"
#include <mutex>
using namespace llvm;
@@ -29,16 +30,17 @@ using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support;
using namespace llvm::support::endian;
+using namespace llvm::sys;
using namespace lld;
using namespace lld::elf;
+std::vector<InputSectionBase *> elf::InputSections;
+
// Returns a string to construct an error message.
-template <class ELFT>
-std::string lld::toString(const InputSectionBase<ELFT> *Sec) {
+std::string lld::toString(const InputSectionBase *Sec) {
// File can be absent if section is synthetic.
- std::string FileName =
- Sec->getFile() ? Sec->getFile()->getName() : "<internal>";
+ std::string FileName = Sec->File ? Sec->File->getName() : "<internal>";
return (FileName + ":(" + Sec->Name + ")").str();
}
@@ -50,91 +52,118 @@ static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
return check(File->getObj().getSectionContents(Hdr));
}
-template <class ELFT>
-InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- uintX_t Flags, uint32_t Type,
- uintX_t Entsize, uint32_t Link,
- uint32_t Info, uintX_t Addralign,
- ArrayRef<uint8_t> Data, StringRef Name,
- Kind SectionKind)
- : InputSectionData(SectionKind, Name, Data,
- !Config->GcSections || !(Flags & SHF_ALLOC)),
- File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link),
- Info(Info), Repl(this) {
+InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags,
+ uint32_t Type, uint64_t Entsize,
+ uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data,
+ StringRef Name, Kind SectionKind)
+ : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info,
+ Link),
+ File(File), Data(Data), Repl(this) {
+ Live = !Config->GcSections || !(Flags & SHF_ALLOC);
+ Assigned = false;
NumRelocations = 0;
AreRelocsRela = false;
// The ELF spec states that a value of 0 means the section has
// no alignment constraits.
- uint64_t V = std::max<uint64_t>(Addralign, 1);
+ uint32_t V = std::max<uint64_t>(Alignment, 1);
if (!isPowerOf2_64(V))
fatal(toString(File) + ": section sh_addralign is not a power of 2");
+ this->Alignment = V;
+}
+// GNU assembler 2.24 and LLVM 4.0.0's MC (the newest release as of
+// March 2017) fail to infer section types for sections starting with
+// ".init_array." or ".fini_array.". They set SHT_PROGBITS instead of
+// SHF_INIT_ARRAY. As a result, the following assembler directive
+// creates ".init_array.100" with SHT_PROGBITS, for example.
+//
+// .section .init_array.100, "aw"
+//
+// This function forces SHT_{INIT,FINI}_ARRAY so that we can handle
+// incorrect inputs as if they were correct from the beginning.
+static uint64_t getType(uint64_t Type, StringRef Name) {
+ if (Type == SHT_PROGBITS && Name.startswith(".init_array."))
+ return SHT_INIT_ARRAY;
+ if (Type == SHT_PROGBITS && Name.startswith(".fini_array."))
+ return SHT_FINI_ARRAY;
+ return Type;
+}
+
+template <class ELFT>
+InputSectionBase::InputSectionBase(elf::ObjectFile<ELFT> *File,
+ const typename ELFT::Shdr *Hdr,
+ StringRef Name, Kind SectionKind)
+ : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK,
+ getType(Hdr->sh_type, Name), Hdr->sh_entsize,
+ Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign,
+ getSectionContents(File, Hdr), Name, SectionKind) {
// We reject object files having insanely large alignments even though
// they are allowed by the spec. I think 4GB is a reasonable limitation.
// We might want to relax this in the future.
- if (V > UINT32_MAX)
+ if (Hdr->sh_addralign > UINT32_MAX)
fatal(toString(File) + ": section sh_addralign is too large");
- Alignment = V;
-
- // If it is not a mergeable section, overwrite the flag so that the flag
- // is consistent with the class. This inconsistency could occur when
- // string merging is disabled using -O0 flag.
- if (!Config->Relocatable && !isa<MergeInputSection<ELFT>>(this))
- this->Flags &= ~(SHF_MERGE | SHF_STRINGS);
}
-template <class ELFT>
-InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
- const Elf_Shdr *Hdr, StringRef Name,
- Kind SectionKind)
- : InputSectionBase(File, Hdr->sh_flags & ~SHF_INFO_LINK, Hdr->sh_type,
- Hdr->sh_entsize, Hdr->sh_link, Hdr->sh_info,
- Hdr->sh_addralign, getSectionContents(File, Hdr), Name,
- SectionKind) {
- this->Offset = Hdr->sh_offset;
-}
-
-template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
- if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this))
+size_t InputSectionBase::getSize() const {
+ if (auto *S = dyn_cast<SyntheticSection>(this))
return S->getSize();
- if (auto *D = dyn_cast<InputSection<ELFT>>(this))
- if (D->getThunksSize() > 0)
- return D->getThunkOff() + D->getThunksSize();
-
return Data.size();
}
-template <class ELFT>
-typename ELFT::uint InputSectionBase<ELFT>::getOffset(uintX_t Offset) const {
+uint64_t InputSectionBase::getOffsetInFile() const {
+ const uint8_t *FileStart = (const uint8_t *)File->MB.getBufferStart();
+ const uint8_t *SecStart = Data.begin();
+ return SecStart - FileStart;
+}
+
+uint64_t SectionBase::getOffset(uint64_t Offset) const {
switch (kind()) {
+ case Output: {
+ auto *OS = cast<OutputSection>(this);
+ // For output sections we treat offset -1 as the end of the section.
+ return Offset == uint64_t(-1) ? OS->Size : Offset;
+ }
case Regular:
- return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
- case Synthetic:
+ return cast<InputSection>(this)->OutSecOff + Offset;
+ case Synthetic: {
+ auto *IS = cast<InputSection>(this);
// For synthetic sections we treat offset -1 as the end of the section.
- // The same approach is used for synthetic symbols (DefinedSynthetic).
- return cast<InputSection<ELFT>>(this)->OutSecOff +
- (Offset == uintX_t(-1) ? getSize() : Offset);
+ return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset);
+ }
case EHFrame:
// The file crtbeginT.o has relocations pointing to the start of an empty
// .eh_frame that is known to be the first in the link. It does that to
// identify the start of the output .eh_frame.
return Offset;
case Merge:
- return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
+ const MergeInputSection *MS = cast<MergeInputSection>(this);
+ if (MS->MergeSec)
+ return MS->MergeSec->OutSecOff + MS->getOffset(Offset);
+ return MS->getOffset(Offset);
}
llvm_unreachable("invalid section kind");
}
+OutputSection *SectionBase::getOutputSection() {
+ if (auto *IS = dyn_cast<InputSection>(this))
+ return IS->OutSec;
+ if (auto *MS = dyn_cast<MergeInputSection>(this))
+ return MS->MergeSec ? MS->MergeSec->OutSec : nullptr;
+ if (auto *EH = dyn_cast<EhInputSection>(this))
+ return EH->EHSec->OutSec;
+ return cast<OutputSection>(this);
+}
+
// Uncompress section contents. Note that this function is called
// from parallel_for_each, so it must be thread-safe.
-template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
- Decompressor Decompressor = check(Decompressor::create(
- Name, toStringRef(Data), ELFT::TargetEndianness == llvm::support::little,
- ELFT::Is64Bits));
+void InputSectionBase::uncompress() {
+ Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data),
+ Config->IsLE, Config->Is64));
- size_t Size = Decompressor.getDecompressedSize();
+ size_t Size = Dec.getDecompressedSize();
char *OutputBuf;
{
static std::mutex Mu;
@@ -142,41 +171,44 @@ template <class ELFT> void InputSectionBase<ELFT>::uncompress() {
OutputBuf = BAlloc.Allocate<char>(Size);
}
- if (Error E = Decompressor.decompress({OutputBuf, Size}))
- fatal(E, toString(this));
+ if (Error E = Dec.decompress({OutputBuf, Size}))
+ fatal(toString(this) +
+ ": decompress failed: " + llvm::toString(std::move(E)));
Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size);
}
-template <class ELFT>
-typename ELFT::uint
-InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) const {
+uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const {
return getOffset(Sym.Value);
}
-template <class ELFT>
-InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const {
+InputSectionBase *InputSectionBase::getLinkOrderDep() const {
if ((Flags & SHF_LINK_ORDER) && Link != 0)
- return getFile()->getSections()[Link];
+ return File->getSections()[Link];
return nullptr;
}
// Returns a source location string. Used to construct an error message.
template <class ELFT>
-std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) {
+std::string InputSectionBase::getLocation(uint64_t Offset) {
+ // We don't have file for synthetic sections.
+ if (getFile<ELFT>() == nullptr)
+ return (Config->OutputFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")")
+ .str();
+
// First check if we can get desired values from debugging information.
- std::string LineInfo = File->getLineInfo(this, Offset);
+ std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset);
if (!LineInfo.empty())
return LineInfo;
// File->SourceFile contains STT_FILE symbol that contains a
// source file name. If it's missing, we use an object file name.
- std::string SrcFile = File->SourceFile;
+ std::string SrcFile = getFile<ELFT>()->SourceFile;
if (SrcFile.empty())
SrcFile = toString(File);
// Find a function symbol that encloses a given location.
- for (SymbolBody *B : File->getSymbols())
- if (auto *D = dyn_cast<DefinedRegular<ELFT>>(B))
+ for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular>(B))
if (D->Section == this && D->Type == STT_FUNC)
if (D->Value <= Offset && Offset < D->Value + D->Size)
return SrcFile + ":(function " + toString(*D) + ")";
@@ -185,69 +217,144 @@ std::string InputSectionBase<ELFT>::getLocation(typename ELFT::uint Offset) {
return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str();
}
-template <class ELFT>
-InputSection<ELFT>::InputSection() : InputSectionBase<ELFT>() {}
+// Returns a source location string. This function is intended to be
+// used for constructing an error message. The returned message looks
+// like this:
+//
+// foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42)
+//
+// Returns an empty string if there's no way to get line info.
+template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) {
+ // Synthetic sections don't have input files.
+ elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+ if (!File)
+ return "";
+
+ Optional<DILineInfo> Info = File->getDILineInfo(this, Offset);
+
+ // File->SourceFile contains STT_FILE symbol, and that is a last resort.
+ if (!Info)
+ return File->SourceFile;
+
+ std::string Path = Info->FileName;
+ std::string Filename = path::filename(Path);
+ std::string Lineno = ":" + std::to_string(Info->Line);
+ if (Filename == Path)
+ return Filename + Lineno;
+ return Filename + Lineno + " (" + Path + Lineno + ")";
+}
+
+// Returns a filename string along with an optional section name. This
+// function is intended to be used for constructing an error
+// message. The returned message looks like this:
+//
+// path/to/foo.o:(function bar)
+//
+// or
+//
+// path/to/foo.o:(function bar) in archive path/to/bar.a
+template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) {
+ // Synthetic sections don't have input files.
+ elf::ObjectFile<ELFT> *File = getFile<ELFT>();
+ std::string Filename = File ? File->getName() : "(internal)";
+
+ std::string Archive;
+ if (!File->ArchiveName.empty())
+ Archive = (" in archive " + File->ArchiveName).str();
+
+ // Find a symbol that encloses a given location.
+ for (SymbolBody *B : getFile<ELFT>()->getSymbols())
+ if (auto *D = dyn_cast<DefinedRegular>(B))
+ if (D->Section == this && D->Value <= Off && Off < D->Value + D->Size)
+ return Filename + ":(" + toString(*D) + ")" + Archive;
-template <class ELFT>
-InputSection<ELFT>::InputSection(uintX_t Flags, uint32_t Type,
- uintX_t Addralign, ArrayRef<uint8_t> Data,
- StringRef Name, Kind K)
- : InputSectionBase<ELFT>(nullptr, Flags, Type,
- /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign,
- Data, Name, K) {}
+ // If there's no symbol, print out the offset in the section.
+ return (Filename + ":(" + Name + "+0x" + utohexstr(Off) + ")" + Archive)
+ .str();
+}
-template <class ELFT>
-InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header, StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {}
+InputSectionBase InputSectionBase::Discarded;
-template <class ELFT>
-bool InputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == Base::Regular || S->kind() == Base::Synthetic;
-}
+InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ ArrayRef<uint8_t> Data, StringRef Name, Kind K)
+ : InputSectionBase(nullptr, Flags, Type,
+ /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data,
+ Name, K) {}
template <class ELFT>
-InputSectionBase<ELFT> *InputSection<ELFT>::getRelocatedSection() {
- assert(this->Type == SHT_RELA || this->Type == SHT_REL);
- ArrayRef<InputSectionBase<ELFT> *> Sections = this->File->getSections();
- return Sections[this->Info];
-}
+InputSection::InputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header, StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {}
-template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
- Thunks.push_back(T);
+bool InputSection::classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Regular ||
+ S->kind() == SectionBase::Synthetic;
}
-template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
- return this->Data.size();
+bool InputSectionBase::classof(const SectionBase *S) {
+ return S->kind() != Output;
}
-template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
- uint64_t Total = 0;
- for (const Thunk<ELFT> *T : Thunks)
- Total += T->size();
- return Total;
+InputSectionBase *InputSection::getRelocatedSection() {
+ assert(this->Type == SHT_RELA || this->Type == SHT_REL);
+ ArrayRef<InputSectionBase *> Sections = this->File->getSections();
+ return Sections[this->Info];
}
-// This is used for -r. We can't use memcpy to copy relocations because we need
-// to update symbol table offset and section index for each relocation. So we
-// copy relocations one by one.
-template <class ELFT>
-template <class RelTy>
-void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
- InputSectionBase<ELFT> *RelocatedSection = getRelocatedSection();
+// This is used for -r and --emit-relocs. We can't use memcpy to copy
+// relocations because we need to update symbol table offset and section index
+// for each relocation. So we copy relocations one by one.
+template <class ELFT, class RelTy>
+void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+ InputSectionBase *RelocatedSection = getRelocatedSection();
+ // Loop is slow and have complexity O(N*M), where N - amount of
+ // relocations and M - amount of symbols in symbol table.
+ // That happens because getSymbolIndex(...) call below performs
+ // simple linear search.
for (const RelTy &Rel : Rels) {
- uint32_t Type = Rel.getType(Config->Mips64EL);
- SymbolBody &Body = this->File->getRelocTargetSym(Rel);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ SymbolBody &Body = this->getFile<ELFT>()->getRelocTargetSym(Rel);
- Elf_Rela *P = reinterpret_cast<Elf_Rela *>(Buf);
+ auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf);
Buf += sizeof(RelTy);
- if (Config->Rela)
+ if (Config->IsRela)
P->r_addend = getAddend<ELFT>(Rel);
- P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
+
+ // 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 = RelocatedSection->OutSec->Addr +
+ RelocatedSection->getOffset(Rel.r_offset);
P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
- Config->Mips64EL);
+ Config->IsMips64EL);
+
+ if (Body.Type == STT_SECTION) {
+ // We combine multiple section symbols into only one per
+ // section. This means we have to update the addend. That is
+ // trivial for Elf_Rela, but for Elf_Rel we have to write to the
+ // section data. We do that by adding to the Relocation vector.
+
+ // .eh_frame is horribly special and can reference discarded sections. To
+ // avoid having to parse and recreate .eh_frame, we just replace any
+ // relocation in it pointing to discarded sections with R_*_NONE, which
+ // hopefully creates a frame that is ignored at runtime.
+ SectionBase *Section = cast<DefinedRegular>(Body).Section;
+ if (Section == &InputSection::Discarded) {
+ P->setSymbolAndType(0, 0, false);
+ continue;
+ }
+
+ if (Config->IsRela) {
+ P->r_addend += Body.getVA() - Section->getOutputSection()->Addr;
+ } else if (Config->Relocatable) {
+ const uint8_t *BufLoc = RelocatedSection->Data.begin() + Rel.r_offset;
+ RelocatedSection->Relocations.push_back(
+ {R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type),
+ &Body});
+ }
+ }
+
}
}
@@ -287,85 +394,52 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A,
template <class ELFT>
static typename ELFT::uint
-getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
+getRelocTargetVA(uint32_t Type, int64_t A, typename ELFT::uint P,
const SymbolBody &Body, RelExpr Expr) {
switch (Expr) {
- case R_HINT:
- case R_TLSDESC_CALL:
- llvm_unreachable("cannot relocate hint relocs");
- case R_TLSLD:
- return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
- case R_TLSLD_PC:
- return In<ELFT>::Got->getTlsIndexVA() + A - P;
- case R_THUNK_ABS:
- return Body.getThunkVA<ELFT>() + A;
- case R_THUNK_PC:
- case R_THUNK_PLT_PC:
- return Body.getThunkVA<ELFT>() + A - P;
- case R_PPC_TOC:
- return getPPC64TocBase() + A;
- case R_TLSGD:
- return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
- In<ELFT>::Got->getSize();
- case R_TLSGD_PC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
- case R_TLSDESC:
- return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
- case R_TLSDESC_PAGE:
- return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
- getAArch64Page(P);
- case R_PLT:
- return Body.getPltVA<ELFT>() + A;
- case R_PLT_PC:
- case R_PPC_PLT_OPD:
- return Body.getPltVA<ELFT>() + A - P;
- case R_SIZE:
- return Body.getSize<ELFT>() + A;
- case R_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA();
- case R_GOTREL_FROM_END:
- return Body.getVA<ELFT>(A) - In<ELFT>::Got->getVA() -
- In<ELFT>::Got->getSize();
- case R_RELAX_TLS_GD_TO_IE_END:
- case R_GOT_FROM_END:
- return Body.getGotOffset<ELFT>() + A - In<ELFT>::Got->getSize();
- case R_RELAX_TLS_GD_TO_IE_ABS:
+ case R_ABS:
+ case R_RELAX_GOT_PC_NOPIC:
+ return Body.getVA(A);
case R_GOT:
+ case R_RELAX_TLS_GD_TO_IE_ABS:
return Body.getGotVA<ELFT>() + A;
- case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
- case R_GOT_PAGE_PC:
- return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
- case R_RELAX_TLS_GD_TO_IE:
- case R_GOT_PC:
- return Body.getGotVA<ELFT>() + A - P;
case R_GOTONLY_PC:
return In<ELFT>::Got->getVA() + A - P;
case R_GOTONLY_PC_FROM_END:
return In<ELFT>::Got->getVA() + A - P + In<ELFT>::Got->getSize();
- case R_RELAX_TLS_LD_TO_LE:
- case R_RELAX_TLS_IE_TO_LE:
- case R_RELAX_TLS_GD_TO_LE:
- case R_TLS:
- // A weak undefined TLS symbol resolves to the base of the TLS
- // block, i.e. gets a value of zero. If we pass --gc-sections to
- // lld and .tbss is not referenced, it gets reclaimed and we don't
- // create a TLS program header. Therefore, we resolve this
- // statically to zero.
- if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) &&
- Body.symbol()->isWeak())
- return 0;
- if (Target->TcbSize)
- return Body.getVA<ELFT>(A) +
- alignTo(Target->TcbSize, Out<ELFT>::TlsPhdr->p_align);
- return Body.getVA<ELFT>(A) - Out<ELFT>::TlsPhdr->p_memsz;
- case R_RELAX_TLS_GD_TO_LE_NEG:
- case R_NEG_TLS:
- return Out<ELF32LE>::TlsPhdr->p_memsz - Body.getVA<ELFT>(A);
- case R_ABS:
- case R_RELAX_GOT_PC_NOPIC:
- return Body.getVA<ELFT>(A);
+ case R_GOTREL:
+ return Body.getVA(A) - In<ELFT>::Got->getVA();
+ case R_GOTREL_FROM_END:
+ return Body.getVA(A) - In<ELFT>::Got->getVA() - In<ELFT>::Got->getSize();
+ case R_GOT_FROM_END:
+ case R_RELAX_TLS_GD_TO_IE_END:
+ return Body.getGotOffset() + A - In<ELFT>::Got->getSize();
case R_GOT_OFF:
- return Body.getGotOffset<ELFT>() + A;
+ return Body.getGotOffset() + A;
+ case R_GOT_PAGE_PC:
+ case R_RELAX_TLS_GD_TO_IE_PAGE_PC:
+ return getAArch64Page(Body.getGotVA<ELFT>() + A) - getAArch64Page(P);
+ case R_GOT_PC:
+ case R_RELAX_TLS_GD_TO_IE:
+ return Body.getGotVA<ELFT>() + A - P;
+ case R_HINT:
+ case R_NONE:
+ case R_TLSDESC_CALL:
+ llvm_unreachable("cannot relocate hint relocs");
+ case R_MIPS_GOTREL:
+ return Body.getVA(A) - In<ELFT>::MipsGot->getGp();
+ case R_MIPS_GOT_GP:
+ return In<ELFT>::MipsGot->getGp() + 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
+ // formula for calculation "AHL + GP - P + 4". For details see p. 4-19 at
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ uint64_t V = In<ELFT>::MipsGot->getGp() + A - P;
+ if (Type == R_MIPS_LO16)
+ V += 4;
+ return V;
+ }
case R_MIPS_GOT_LOCAL_PAGE:
// If relocation against MIPS local symbol requires GOT entry, this entry
// should be initialized by 'page address'. This address is high 16-bits
@@ -381,8 +455,6 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
return In<ELFT>::MipsGot->getVA() +
In<ELFT>::MipsGot->getBodyEntryOffset(Body, A) -
In<ELFT>::MipsGot->getGp();
- case R_MIPS_GOTREL:
- return Body.getVA<ELFT>(A) - In<ELFT>::MipsGot->getGp();
case R_MIPS_TLSGD:
return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
In<ELFT>::MipsGot->getGlobalDynOffset(Body) -
@@ -390,40 +462,82 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
case R_MIPS_TLSLD:
return In<ELFT>::MipsGot->getVA() + In<ELFT>::MipsGot->getTlsOffset() +
In<ELFT>::MipsGot->getTlsIndexOff() - In<ELFT>::MipsGot->getGp();
+ case R_PAGE_PC:
+ case R_PLT_PAGE_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
+ return getAArch64Page(A);
+ return getAArch64Page(Body.getVA(A)) - getAArch64Page(P);
+ case R_PC:
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
+ // On ARM and AArch64 a branch to an undefined weak resolves to the
+ // next instruction, otherwise the place.
+ if (Config->EMachine == EM_ARM)
+ return getARMUndefinedRelativeWeakVA(Type, A, P);
+ if (Config->EMachine == EM_AARCH64)
+ return getAArch64UndefinedRelativeWeakVA(Type, A, P);
+ }
+ return Body.getVA(A) - P;
+ case R_PLT:
+ return Body.getPltVA() + A;
+ case R_PLT_PC:
+ case R_PPC_PLT_OPD:
+ return Body.getPltVA() + A - P;
case R_PPC_OPD: {
- uint64_t SymVA = Body.getVA<ELFT>(A);
+ uint64_t SymVA = Body.getVA(A);
// If we have an undefined weak symbol, we might get here with a symbol
// address of zero. That could overflow, but the code must be unreachable,
// so don't bother doing anything at all.
if (!SymVA)
return 0;
- if (Out<ELF64BE>::Opd) {
+ if (Out::Opd) {
// If this is a local call, and we currently have the address of a
// function-descriptor, get the underlying code address instead.
- uint64_t OpdStart = Out<ELF64BE>::Opd->Addr;
- uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->Size;
+ uint64_t OpdStart = Out::Opd->Addr;
+ uint64_t OpdEnd = OpdStart + Out::Opd->Size;
bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd;
if (InOpd)
- SymVA = read64be(&Out<ELF64BE>::OpdBuf[SymVA - OpdStart]);
+ SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]);
}
return SymVA - P;
}
- case R_PC:
- if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) {
- // On ARM and AArch64 a branch to an undefined weak resolves to the
- // next instruction, otherwise the place.
- if (Config->EMachine == EM_ARM)
- return getARMUndefinedRelativeWeakVA(Type, A, P);
- if (Config->EMachine == EM_AARCH64)
- return getAArch64UndefinedRelativeWeakVA(Type, A, P);
- }
+ case R_PPC_TOC:
+ return getPPC64TocBase() + A;
case R_RELAX_GOT_PC:
- return Body.getVA<ELFT>(A) - P;
- case R_PLT_PAGE_PC:
- case R_PAGE_PC:
- if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
- return getAArch64Page(A);
- return getAArch64Page(Body.getVA<ELFT>(A)) - getAArch64Page(P);
+ return Body.getVA(A) - P;
+ case R_RELAX_TLS_GD_TO_LE:
+ case R_RELAX_TLS_IE_TO_LE:
+ case R_RELAX_TLS_LD_TO_LE:
+ case R_TLS:
+ // A weak undefined TLS symbol resolves to the base of the TLS
+ // block, i.e. gets a value of zero. If we pass --gc-sections to
+ // lld and .tbss is not referenced, it gets reclaimed and we don't
+ // create a TLS program header. Therefore, we resolve this
+ // statically to zero.
+ if (Body.isTls() && (Body.isLazy() || Body.isUndefined()) &&
+ Body.symbol()->isWeak())
+ return 0;
+ if (Target->TcbSize)
+ return Body.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align);
+ return Body.getVA(A) - Out::TlsPhdr->p_memsz;
+ case R_RELAX_TLS_GD_TO_LE_NEG:
+ case R_NEG_TLS:
+ return Out::TlsPhdr->p_memsz - Body.getVA(A);
+ case R_SIZE:
+ return Body.getSize<ELFT>() + A;
+ case R_TLSDESC:
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A;
+ case R_TLSDESC_PAGE:
+ return getAArch64Page(In<ELFT>::Got->getGlobalDynAddr(Body) + A) -
+ getAArch64Page(P);
+ case R_TLSGD:
+ return In<ELFT>::Got->getGlobalDynOffset(Body) + A -
+ In<ELFT>::Got->getSize();
+ case R_TLSGD_PC:
+ return In<ELFT>::Got->getGlobalDynAddr(Body) + A - P;
+ case R_TLSLD:
+ return In<ELFT>::Got->getTlsIndexOff() + A - In<ELFT>::Got->getSize();
+ case R_TLSLD_PC:
+ return In<ELFT>::Got->getTlsIndexVA() + A - P;
}
llvm_unreachable("Invalid expression");
}
@@ -435,57 +549,62 @@ getRelocTargetVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
// treatement such as GOT or PLT (because at runtime no one refers them).
// So, we handle relocations for non-alloc sections directly in this
// function as a performance optimization.
-template <class ELFT>
-template <class RelTy>
-void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
+template <class ELFT, class RelTy>
+void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
for (const RelTy &Rel : Rels) {
- uint32_t Type = Rel.getType(Config->Mips64EL);
- uintX_t Offset = this->getOffset(Rel.r_offset);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ uint64_t Offset = getOffset(Rel.r_offset);
uint8_t *BufLoc = Buf + Offset;
- uintX_t Addend = getAddend<ELFT>(Rel);
+ int64_t Addend = getAddend<ELFT>(Rel);
if (!RelTy::IsRela)
Addend += Target->getImplicitAddend(BufLoc, Type);
- SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
- if (Target->getRelExpr(Type, Sym) != R_ABS) {
- error(this->getLocation(Offset) + ": has non-ABS reloc");
+ SymbolBody &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel);
+ RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc);
+ if (Expr == R_NONE)
+ continue;
+ if (Expr != R_ABS) {
+ error(this->getLocation<ELFT>(Offset) + ": has non-ABS reloc");
return;
}
- uintX_t AddrLoc = this->OutSec->Addr + Offset;
+ uint64_t AddrLoc = this->OutSec->Addr + Offset;
uint64_t SymVA = 0;
- if (!Sym.isTls() || Out<ELFT>::TlsPhdr)
- SymVA = SignExtend64<sizeof(uintX_t) * 8>(
+ if (!Sym.isTls() || Out::TlsPhdr)
+ SymVA = SignExtend64<sizeof(typename ELFT::uint) * 8>(
getRelocTargetVA<ELFT>(Type, Addend, AddrLoc, Sym, R_ABS));
Target->relocateOne(BufLoc, Type, SymVA);
}
}
+template <class ELFT> elf::ObjectFile<ELFT> *InputSectionBase::getFile() const {
+ return cast_or_null<elf::ObjectFile<ELFT>>(File);
+}
+
template <class ELFT>
-void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
+void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
// scanReloc function in Writer.cpp constructs Relocations
// vector only for SHF_ALLOC'ed sections. For other sections,
// we handle relocations directly here.
- auto *IS = dyn_cast<InputSection<ELFT>>(this);
+ auto *IS = dyn_cast<InputSection>(this);
if (IS && !(IS->Flags & SHF_ALLOC)) {
if (IS->AreRelocsRela)
- IS->relocateNonAlloc(Buf, IS->relas());
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template relas<ELFT>());
else
- IS->relocateNonAlloc(Buf, IS->rels());
+ IS->relocateNonAlloc<ELFT>(Buf, IS->template rels<ELFT>());
return;
}
- const unsigned Bits = sizeof(uintX_t) * 8;
+ const unsigned Bits = sizeof(typename ELFT::uint) * 8;
for (const Relocation &Rel : Relocations) {
- uintX_t Offset = getOffset(Rel.Offset);
+ uint64_t Offset = getOffset(Rel.Offset);
uint8_t *BufLoc = Buf + Offset;
uint32_t Type = Rel.Type;
- uintX_t A = Rel.Addend;
- uintX_t AddrLoc = OutSec->Addr + Offset;
+ uint64_t AddrLoc = getOutputSection()->Addr + Offset;
RelExpr Expr = Rel.Expr;
uint64_t TargetVA = SignExtend64<Bits>(
- getRelocTargetVA<ELFT>(Type, A, AddrLoc, *Rel.Sym, Expr));
+ getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr));
switch (Expr) {
case R_RELAX_GOT_PC:
@@ -520,67 +639,54 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
}
}
-template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
+template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {
if (this->Type == SHT_NOBITS)
return;
- if (auto *S = dyn_cast<SyntheticSection<ELFT>>(this)) {
+ if (auto *S = dyn_cast<SyntheticSection>(this)) {
S->writeTo(Buf + OutSecOff);
return;
}
- // If -r is given, then an InputSection may be a relocation section.
+ // If -r or --emit-relocs is given, then an InputSection
+ // may be a relocation section.
if (this->Type == SHT_RELA) {
- copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
+ copyRelocations<ELFT>(Buf + OutSecOff,
+ this->template getDataAs<typename ELFT::Rela>());
return;
}
if (this->Type == SHT_REL) {
- copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>());
+ copyRelocations<ELFT>(Buf + OutSecOff,
+ this->template getDataAs<typename ELFT::Rel>());
return;
}
- // Copy section contents from source object file to output file.
- ArrayRef<uint8_t> Data = this->Data;
+ // Copy section contents from source object file to output file
+ // and then apply relocations.
memcpy(Buf + OutSecOff, Data.data(), Data.size());
-
- // Iterate over all relocation sections that apply to this section.
uint8_t *BufEnd = Buf + OutSecOff + Data.size();
- this->relocate(Buf, BufEnd);
-
- // The section might have a data/code generated by the linker and need
- // to be written after the section. Usually these are thunks - small piece
- // of code used to jump between "incompatible" functions like PIC and non-PIC
- // or if the jump target too far and its address does not fit to the short
- // jump istruction.
- if (!Thunks.empty()) {
- Buf += OutSecOff + getThunkOff();
- for (const Thunk<ELFT> *T : Thunks) {
- T->writeTo(Buf);
- Buf += T->size();
- }
- }
+ this->relocate<ELFT>(Buf, BufEnd);
}
-template <class ELFT>
-void InputSection<ELFT>::replace(InputSection<ELFT> *Other) {
+void InputSection::replace(InputSection *Other) {
this->Alignment = std::max(this->Alignment, Other->Alignment);
Other->Repl = this->Repl;
Other->Live = false;
}
template <class ELFT>
-EhInputSection<ELFT>::EhInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header, StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::EHFrame) {
+EhInputSection::EhInputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {
// Mark .eh_frame sections as live by default because there are
// usually no relocations that point to .eh_frames. Otherwise,
// the garbage collector would drop all .eh_frame sections.
this->Live = true;
}
-template <class ELFT>
-bool EhInputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == InputSectionBase<ELFT>::EHFrame;
+bool EhInputSection::classof(const SectionBase *S) {
+ return S->kind() == InputSectionBase::EHFrame;
}
// Returns the index of the first relocation that points to a region between
@@ -604,24 +710,23 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
// .eh_frame is a sequence of CIE or FDE records.
// This function splits an input section into records and returns them.
-template <class ELFT> void EhInputSection<ELFT>::split() {
+template <class ELFT> void EhInputSection::split() {
// Early exit if already split.
if (!this->Pieces.empty())
return;
if (this->NumRelocations) {
if (this->AreRelocsRela)
- split(this->relas());
+ split<ELFT>(this->relas<ELFT>());
else
- split(this->rels());
+ split<ELFT>(this->rels<ELFT>());
return;
}
- split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+ split<ELFT>(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
}
-template <class ELFT>
-template <class RelTy>
-void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
+template <class ELFT, class RelTy>
+void EhInputSection::split(ArrayRef<RelTy> Rels) {
ArrayRef<uint8_t> Data = this->Data;
unsigned RelI = 0;
for (size_t Off = 0, End = Data.size(); Off != End;) {
@@ -650,9 +755,7 @@ static size_t findNull(ArrayRef<uint8_t> A, size_t EntSize) {
// Split SHF_STRINGS section. Such section is a sequence of
// null-terminated strings.
-template <class ELFT>
-void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
+void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) {
size_t Off = 0;
bool IsAlloc = this->Flags & SHF_ALLOC;
while (!Data.empty()) {
@@ -669,9 +772,8 @@ void MergeInputSection<ELFT>::splitStrings(ArrayRef<uint8_t> Data,
// Split non-SHF_STRINGS section. Such section is a sequence of
// fixed size records.
-template <class ELFT>
-void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
- size_t EntSize) {
+void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data,
+ size_t EntSize) {
size_t Size = Data.size();
assert((Size % EntSize) == 0);
bool IsAlloc = this->Flags & SHF_ALLOC;
@@ -682,10 +784,10 @@ void MergeInputSection<ELFT>::splitNonStrings(ArrayRef<uint8_t> Data,
}
template <class ELFT>
-MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
- const Elf_Shdr *Header,
- StringRef Name)
- : InputSectionBase<ELFT>(F, Header, Name, InputSectionBase<ELFT>::Merge) {}
+MergeInputSection::MergeInputSection(elf::ObjectFile<ELFT> *F,
+ const typename ELFT::Shdr *Header,
+ StringRef Name)
+ : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}
// This function is called after we obtain a complete list of input sections
// that need to be linked. This is responsible to split section contents
@@ -693,28 +795,26 @@ MergeInputSection<ELFT>::MergeInputSection(elf::ObjectFile<ELFT> *F,
//
// Note that this function is called from parallel_for_each. This must be
// thread-safe (i.e. no memory allocation from the pools).
-template <class ELFT> void MergeInputSection<ELFT>::splitIntoPieces() {
+void MergeInputSection::splitIntoPieces() {
ArrayRef<uint8_t> Data = this->Data;
- uintX_t EntSize = this->Entsize;
+ uint64_t EntSize = this->Entsize;
if (this->Flags & SHF_STRINGS)
splitStrings(Data, EntSize);
else
splitNonStrings(Data, EntSize);
if (Config->GcSections && (this->Flags & SHF_ALLOC))
- for (uintX_t Off : LiveOffsets)
+ for (uint64_t Off : LiveOffsets)
this->getSectionPiece(Off)->Live = true;
}
-template <class ELFT>
-bool MergeInputSection<ELFT>::classof(const InputSectionData *S) {
- return S->kind() == InputSectionBase<ELFT>::Merge;
+bool MergeInputSection::classof(const SectionBase *S) {
+ return S->kind() == InputSectionBase::Merge;
}
// Do binary search to get a section piece at a given input offset.
-template <class ELFT>
-SectionPiece *MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) {
- auto *This = static_cast<const MergeInputSection<ELFT> *>(this);
+SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) {
+ auto *This = static_cast<const MergeInputSection *>(this);
return const_cast<SectionPiece *>(This->getSectionPiece(Offset));
}
@@ -731,17 +831,15 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) {
return Comp(Value, *First) ? First : First + 1;
}
-template <class ELFT>
-const SectionPiece *
-MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
- uintX_t Size = this->Data.size();
+const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {
+ uint64_t Size = this->Data.size();
if (Offset >= Size)
fatal(toString(this) + ": entry is past the end of the section");
// Find the element this offset points to.
auto I = fastUpperBound(
Pieces.begin(), Pieces.end(), Offset,
- [](const uintX_t &A, const SectionPiece &B) { return A < B.InputOff; });
+ [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; });
--I;
return &*I;
}
@@ -749,8 +847,7 @@ MergeInputSection<ELFT>::getSectionPiece(uintX_t Offset) const {
// Returns the offset in an output section for a given input offset.
// Because contents of a mergeable section is not contiguous in output,
// it is not just an addition to a base output offset.
-template <class ELFT>
-typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+uint64_t MergeInputSection::getOffset(uint64_t Offset) const {
// Initialize OffsetMap lazily.
std::call_once(InitOffsetMap, [&] {
OffsetMap.reserve(Pieces.size());
@@ -772,31 +869,63 @@ typename ELFT::uint MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
if (!Piece.Live)
return 0;
- uintX_t Addend = Offset - Piece.InputOff;
+ uint64_t Addend = Offset - Piece.InputOff;
return Piece.OutputOff + Addend;
}
-template class elf::InputSectionBase<ELF32LE>;
-template class elf::InputSectionBase<ELF32BE>;
-template class elf::InputSectionBase<ELF64LE>;
-template class elf::InputSectionBase<ELF64BE>;
-
-template class elf::InputSection<ELF32LE>;
-template class elf::InputSection<ELF32BE>;
-template class elf::InputSection<ELF64LE>;
-template class elf::InputSection<ELF64BE>;
-
-template class elf::EhInputSection<ELF32LE>;
-template class elf::EhInputSection<ELF32BE>;
-template class elf::EhInputSection<ELF64LE>;
-template class elf::EhInputSection<ELF64BE>;
-
-template class elf::MergeInputSection<ELF32LE>;
-template class elf::MergeInputSection<ELF32BE>;
-template class elf::MergeInputSection<ELF64LE>;
-template class elf::MergeInputSection<ELF64BE>;
-
-template std::string lld::toString(const InputSectionBase<ELF32LE> *);
-template std::string lld::toString(const InputSectionBase<ELF32BE> *);
-template std::string lld::toString(const InputSectionBase<ELF64LE> *);
-template std::string lld::toString(const InputSectionBase<ELF64BE> *);
+template InputSection::InputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template InputSection::InputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getSrcMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getSrcMsg<ELF64BE>(uint64_t);
+
+template std::string InputSectionBase::getObjMsg<ELF32LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF32BE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64LE>(uint64_t);
+template std::string InputSectionBase::getObjMsg<ELF64BE>(uint64_t);
+
+template void InputSection::writeTo<ELF32LE>(uint8_t *);
+template void InputSection::writeTo<ELF32BE>(uint8_t *);
+template void InputSection::writeTo<ELF64LE>(uint8_t *);
+template void InputSection::writeTo<ELF64BE>(uint8_t *);
+
+template elf::ObjectFile<ELF32LE> *InputSectionBase::getFile<ELF32LE>() const;
+template elf::ObjectFile<ELF32BE> *InputSectionBase::getFile<ELF32BE>() const;
+template elf::ObjectFile<ELF64LE> *InputSectionBase::getFile<ELF64LE>() const;
+template elf::ObjectFile<ELF64BE> *InputSectionBase::getFile<ELF64BE>() const;
+
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template MergeInputSection::MergeInputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32LE> *,
+ const ELF32LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF32BE> *,
+ const ELF32BE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64LE> *,
+ const ELF64LE::Shdr *, StringRef);
+template EhInputSection::EhInputSection(elf::ObjectFile<ELF64BE> *,
+ const ELF64BE::Shdr *, StringRef);
+
+template void EhInputSection::split<ELF32LE>();
+template void EhInputSection::split<ELF32BE>();
+template void EhInputSection::split<ELF64LE>();
+template void EhInputSection::split<ELF64BE>();
diff --git a/ELF/InputSection.h b/ELF/InputSection.h
index 3f3a055dcc33..57458588b690 100644
--- a/ELF/InputSection.h
+++ b/ELF/InputSection.h
@@ -27,97 +27,115 @@ class DefinedCommon;
class SymbolBody;
struct SectionPiece;
-template <class ELFT> class DefinedRegular;
+class DefinedRegular;
+class SyntheticSection;
+template <class ELFT> class EhFrameSection;
+class MergeSyntheticSection;
template <class ELFT> class ObjectFile;
-template <class ELFT> class OutputSection;
-class OutputSectionBase;
-
-// We need non-template input section class to store symbol layout
-// in linker script parser structures, where we do not have ELFT
-// template parameter. For each scripted output section symbol we
-// store pointer to preceding InputSectionData object or nullptr,
-// if symbol should be placed at the very beginning of the output
-// section
-class InputSectionData {
+class OutputSection;
+
+// This is the base class of all sections that lld handles. Some are sections in
+// input files, some are sections in the produced output file and some exist
+// just as a convenience for implementing special ways of combining some
+// sections.
+class SectionBase {
public:
- enum Kind { Regular, EHFrame, Merge, Synthetic, };
+ enum Kind { Regular, EHFrame, Merge, Synthetic, Output };
- // The garbage collector sets sections' Live bits.
- // If GC is disabled, all sections are considered live by default.
- InputSectionData(Kind SectionKind, StringRef Name, ArrayRef<uint8_t> Data,
- bool Live)
- : SectionKind(SectionKind), Live(Live), Assigned(false), Name(Name),
- Data(Data) {}
+ Kind kind() const { return (Kind)SectionKind; }
+
+ StringRef Name;
-private:
unsigned SectionKind : 3;
-public:
- Kind kind() const { return (Kind)SectionKind; }
+ // The next two bit fields are only used by InputSectionBase, but we
+ // put them here so the struct packs better.
+
+ // The garbage collector sets sections' Live bits.
+ // If GC is disabled, all sections are considered live by default.
+ unsigned Live : 1; // for garbage collection
+ unsigned Assigned : 1; // for linker script
- unsigned Live : 1; // for garbage collection
- unsigned Assigned : 1; // for linker script
uint32_t Alignment;
- StringRef Name;
- ArrayRef<uint8_t> Data;
- template <typename T> llvm::ArrayRef<T> getDataAs() const {
- size_t S = Data.size();
- assert(S % sizeof(T) == 0);
- return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ // These corresponds to the fields in Elf_Shdr.
+ uint64_t Flags;
+ uint64_t Entsize;
+ uint32_t Type;
+ uint32_t Link;
+ uint32_t Info;
+
+ OutputSection *getOutputSection();
+ const OutputSection *getOutputSection() const {
+ return const_cast<SectionBase *>(this)->getOutputSection();
}
- std::vector<Relocation> Relocations;
+ // Translate an offset in the input section to an offset in the output
+ // section.
+ uint64_t getOffset(uint64_t Offset) const;
+
+ uint64_t getOffset(const DefinedRegular &Sym) const;
+
+protected:
+ SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags,
+ uint64_t Entsize, uint64_t Alignment, uint32_t Type,
+ uint32_t Info, uint32_t Link)
+ : Name(Name), SectionKind(SectionKind), Alignment(Alignment),
+ Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) {
+ Live = false;
+ Assigned = false;
+ }
};
// This corresponds to a section of an input file.
-template <class ELFT> class InputSectionBase : public InputSectionData {
-protected:
- typedef typename ELFT::Chdr Elf_Chdr;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
+class InputSectionBase : public SectionBase {
+public:
+ static bool classof(const SectionBase *S);
// The file this section is from.
- ObjectFile<ELFT> *File;
+ InputFile *File;
-public:
- // These corresponds to the fields in Elf_Shdr.
- uintX_t Flags;
- uintX_t Offset = 0;
- uintX_t Entsize;
- uint32_t Type;
- uint32_t Link;
- uint32_t Info;
+ ArrayRef<uint8_t> Data;
+ uint64_t getOffsetInFile() const;
+
+ static InputSectionBase Discarded;
InputSectionBase()
- : InputSectionData(Regular, "", ArrayRef<uint8_t>(), false), Repl(this) {
+ : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0,
+ /*Type*/ 0,
+ /*Info*/ 0, /*Link*/ 0),
+ Repl(this) {
+ Live = false;
+ Assigned = false;
NumRelocations = 0;
AreRelocsRela = false;
}
- InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ template <class ELFT>
+ InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header,
StringRef Name, Kind SectionKind);
- InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type,
- uintX_t Entsize, uint32_t Link, uint32_t Info,
- uintX_t Addralign, ArrayRef<uint8_t> Data, StringRef Name,
+
+ InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type,
+ uint64_t Entsize, uint32_t Link, uint32_t Info,
+ uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name,
Kind SectionKind);
- OutputSectionBase *OutSec = nullptr;
+ OutputSection *OutSec = nullptr;
// Relocations that refer to this section.
- const Elf_Rel *FirstRelocation = nullptr;
+ const void *FirstRelocation = nullptr;
unsigned NumRelocations : 31;
unsigned AreRelocsRela : 1;
- ArrayRef<Elf_Rel> rels() const {
+ template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const {
assert(!AreRelocsRela);
- return llvm::makeArrayRef(FirstRelocation, NumRelocations);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rel *>(FirstRelocation),
+ NumRelocations);
}
- ArrayRef<Elf_Rela> relas() const {
+ template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const {
assert(AreRelocsRela);
- return llvm::makeArrayRef(static_cast<const Elf_Rela *>(FirstRelocation),
- NumRelocations);
+ return llvm::makeArrayRef(
+ static_cast<const typename ELFT::Rela *>(FirstRelocation),
+ NumRelocations);
}
// This pointer points to the "real" instance of this instance.
@@ -125,25 +143,38 @@ public:
// Repl pointer of one section points to another section. So,
// if you need to get a pointer to this instance, do not use
// this but instead this->Repl.
- InputSectionBase<ELFT> *Repl;
+ InputSectionBase *Repl;
+
+ // InputSections that are dependent on us (reverse dependency for GC)
+ llvm::TinyPtrVector<InputSectionBase *> DependentSections;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
- ObjectFile<ELFT> *getFile() const { return File; }
- llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); }
- uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
+ template <class ELFT> ObjectFile<ELFT> *getFile() const;
+
+ template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const {
+ return getFile<ELFT>()->getObj();
+ }
+
InputSectionBase *getLinkOrderDep() const;
- // Translate an offset in the input section to an offset in the output
- // section.
- uintX_t getOffset(uintX_t Offset) const;
void uncompress();
// Returns a source location string. Used to construct an error message.
- std::string getLocation(uintX_t Offset);
+ template <class ELFT> std::string getLocation(uint64_t Offset);
+ template <class ELFT> std::string getSrcMsg(uint64_t Offset);
+ template <class ELFT> std::string getObjMsg(uint64_t Offset);
+
+ template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd);
+
+ std::vector<Relocation> Relocations;
- void relocate(uint8_t *Buf, uint8_t *BufEnd);
+ template <typename T> llvm::ArrayRef<T> getDataAs() const {
+ size_t S = Data.size();
+ assert(S % sizeof(T) == 0);
+ return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+ }
};
// SectionPiece represents a piece of splittable section contents.
@@ -162,26 +193,23 @@ static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t),
"SectionPiece is too big");
// This corresponds to a SHF_MERGE section of an input file.
-template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::Shdr Elf_Shdr;
-
+class MergeInputSection : public InputSectionBase {
public:
- MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header,
+ template <class ELFT>
+ MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
StringRef Name);
- static bool classof(const InputSectionData *S);
+ static bool classof(const SectionBase *S);
void splitIntoPieces();
// Mark the piece at a given offset live. Used by GC.
- void markLiveAt(uintX_t Offset) {
+ void markLiveAt(uint64_t Offset) {
assert(this->Flags & llvm::ELF::SHF_ALLOC);
LiveOffsets.insert(Offset);
}
// Translate an offset in the input section to an offset
// in the output section.
- uintX_t getOffset(uintX_t Offset) const;
+ uint64_t getOffset(uint64_t Offset) const;
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
@@ -203,8 +231,13 @@ public:
}
// Returns the SectionPiece at a given input section offset.
- SectionPiece *getSectionPiece(uintX_t Offset);
- const SectionPiece *getSectionPiece(uintX_t Offset) const;
+ SectionPiece *getSectionPiece(uint64_t Offset);
+ const SectionPiece *getSectionPiece(uint64_t Offset) const;
+
+ // MergeInputSections are aggregated to a synthetic input sections,
+ // and then added to an OutputSection. This pointer points to a
+ // synthetic MergeSyntheticSection which this section belongs to.
+ MergeSyntheticSection *MergeSec = nullptr;
private:
void splitStrings(ArrayRef<uint8_t> A, size_t Size);
@@ -212,18 +245,18 @@ private:
std::vector<uint32_t> Hashes;
- mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap;
+ mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;
mutable std::once_flag InitOffsetMap;
- llvm::DenseSet<uintX_t> LiveOffsets;
+ llvm::DenseSet<uint64_t> LiveOffsets;
};
struct EhSectionPiece : public SectionPiece {
- EhSectionPiece(size_t Off, InputSectionData *ID, uint32_t Size,
+ EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size,
unsigned FirstRelocation)
: SectionPiece(Off, false), ID(ID), Size(Size),
FirstRelocation(FirstRelocation) {}
- InputSectionData *ID;
+ InputSectionBase *ID;
uint32_t Size;
uint32_t size() const { return Size; }
@@ -232,85 +265,65 @@ struct EhSectionPiece : public SectionPiece {
};
// This corresponds to a .eh_frame section of an input file.
-template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
+class EhInputSection : public InputSectionBase {
public:
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::uint uintX_t;
- EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
- static bool classof(const InputSectionData *S);
- void split();
- template <class RelTy> void split(ArrayRef<RelTy> Rels);
+ template <class ELFT>
+ EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+ StringRef Name);
+ static bool classof(const SectionBase *S);
+ template <class ELFT> void split();
+ template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels);
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
std::vector<EhSectionPiece> Pieces;
+ SyntheticSection *EHSec = nullptr;
};
-// This corresponds to a non SHF_MERGE section of an input file.
-template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
- typedef InputSectionBase<ELFT> Base;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::uint uintX_t;
- typedef InputSectionData::Kind Kind;
-
+// This is a section that is added directly to an output section
+// instead of needing special combination via a synthetic section. This
+// includes all input sections with the exceptions of SHF_MERGE and
+// .eh_frame. It also includes the synthetic sections themselves.
+class InputSection : public InputSectionBase {
public:
- InputSection();
- InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
- ArrayRef<uint8_t> Data, StringRef Name,
- Kind K = InputSectionData::Regular);
- InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
-
- static InputSection<ELFT> Discarded;
+ InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment,
+ ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular);
+ template <class ELFT>
+ InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header,
+ StringRef Name);
// Write this section to a mmap'ed file, assuming Buf is pointing to
// beginning of the output section.
- void writeTo(uint8_t *Buf);
+ template <class ELFT> void writeTo(uint8_t *Buf);
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
- // InputSection that is dependent on us (reverse dependency for GC)
- InputSectionBase<ELFT> *DependentSection = nullptr;
-
- static bool classof(const InputSectionData *S);
-
- InputSectionBase<ELFT> *getRelocatedSection();
+ static bool classof(const SectionBase *S);
- // Register thunk related to the symbol. When the section is written
- // to a mmap'ed file, target is requested to write an actual thunk code.
- // Now thunks is supported for MIPS and ARM target only.
- void addThunk(const Thunk<ELFT> *T);
+ InputSectionBase *getRelocatedSection();
- // The offset of synthetic thunk code from beginning of this section.
- uint64_t getThunkOff() const;
-
- // Size of chunk with thunks code.
- uint64_t getThunksSize() const;
-
- template <class RelTy>
+ template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
// Used by ICF.
uint32_t Class[2] = {0, 0};
// Called by ICF to merge two input sections.
- void replace(InputSection<ELFT> *Other);
+ void replace(InputSection *Other);
private:
- template <class RelTy>
+ template <class ELFT, class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
-
- llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
};
-template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded;
+// The list of all input sections.
+extern std::vector<InputSectionBase *> InputSections;
+
} // namespace elf
-template <class ELFT> std::string toString(const elf::InputSectionBase<ELFT> *);
+std::string toString(const elf::InputSectionBase *);
} // namespace lld
#endif
diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp
index b342b6195f1d..dd435173101a 100644
--- a/ELF/LTO.cpp
+++ b/ELF/LTO.cpp
@@ -12,12 +12,13 @@
#include "Error.h"
#include "InputFiles.h"
#include "Symbols.h"
+#include "lld/Core/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/LTO/Caching.h"
#include "llvm/LTO/Config.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/SymbolicFile.h"
@@ -46,7 +47,7 @@ static void saveBuffer(StringRef Buffer, const Twine &Path) {
std::error_code EC;
raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None);
if (EC)
- error(EC, "cannot create " + Path);
+ error("cannot create " + Path + ": " + EC.message());
OS << Buffer;
}
@@ -73,6 +74,7 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.Options.RelaxELFRelocations = true;
Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static;
+ Conf.CodeModel = GetCodeModelFromCMModel();
Conf.DisableVerify = Config->DisableVerify;
Conf.DiagHandler = diagnosticHandler;
Conf.OptLevel = Config->LTOO;
@@ -81,6 +83,10 @@ static std::unique_ptr<lto::LTO> createLTO() {
Conf.OptPipeline = Config->LTONewPmPasses;
Conf.AAPipeline = Config->LTOAAPipeline;
+ // Set up optimization remarks if we've been asked to.
+ Conf.RemarksFilename = Config->OptRemarksFilename;
+ Conf.RemarksWithHotness = Config->OptRemarksWithHotness;
+
if (Config->SaveTemps)
checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".",
/*UseInputModulePath*/ true));
@@ -96,12 +102,12 @@ BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {}
BitcodeCompiler::~BitcodeCompiler() = default;
-template <class ELFT> static void undefine(Symbol *S) {
- replaceBody<Undefined<ELFT>>(S, S->body()->getName(), /*IsLocal=*/false,
- STV_DEFAULT, S->body()->Type, nullptr);
+static void undefine(Symbol *S) {
+ replaceBody<Undefined>(S, S->body()->getName(), /*IsLocal=*/false,
+ STV_DEFAULT, S->body()->Type, nullptr);
}
-template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
+void BitcodeCompiler::add(BitcodeFile &F) {
lto::InputFile &Obj = *F.Obj;
unsigned SymNum = 0;
std::vector<Symbol *> Syms = F.getSymbols();
@@ -119,14 +125,12 @@ template <class ELFT> void BitcodeCompiler::add(BitcodeFile &F) {
// flags an undefined in IR with a definition in ASM as prevailing.
// Once IRObjectFile is fixed to report only one symbol this hack can
// be removed.
- R.Prevailing =
- !(ObjSym.getFlags() & object::BasicSymbolRef::SF_Undefined) &&
- B->File == &F;
+ R.Prevailing = !ObjSym.isUndefined() && B->File == &F;
R.VisibleToRegularObj =
Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym());
if (R.Prevailing)
- undefine<ELFT>(Sym);
+ undefine(Sym);
}
checkError(LTOObj->add(std::move(F.Obj), Resols));
}
@@ -137,17 +141,34 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
std::vector<InputFile *> Ret;
unsigned MaxTasks = LTOObj->getMaxTasks();
Buff.resize(MaxTasks);
-
- checkError(LTOObj->run([&](size_t Task) {
- return llvm::make_unique<lto::NativeObjectStream>(
- llvm::make_unique<raw_svector_ostream>(Buff[Task]));
- }));
+ Files.resize(MaxTasks);
+
+ // The --thinlto-cache-dir option specifies the path to a directory in which
+ // to cache native object files for ThinLTO incremental builds. If a path was
+ // specified, configure LTO to use it as the cache directory.
+ lto::NativeObjectCache Cache;
+ if (!Config->ThinLTOCacheDir.empty())
+ Cache = check(
+ lto::localCache(Config->ThinLTOCacheDir,
+ [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) {
+ Files[Task] = std::move(MB);
+ }));
+
+ checkError(LTOObj->run(
+ [&](size_t Task) {
+ return llvm::make_unique<lto::NativeObjectStream>(
+ llvm::make_unique<raw_svector_ostream>(Buff[Task]));
+ },
+ Cache));
+
+ if (!Config->ThinLTOCacheDir.empty())
+ pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy);
for (unsigned I = 0; I != MaxTasks; ++I) {
if (Buff[I].empty())
continue;
if (Config->SaveTemps) {
- if (MaxTasks == 1)
+ if (I == 0)
saveBuffer(Buff[I], Config->OutputFile + ".lto.o");
else
saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o");
@@ -155,10 +176,10 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp"));
Ret.push_back(Obj);
}
+
+ for (std::unique_ptr<MemoryBuffer> &File : Files)
+ if (File)
+ Ret.push_back(createObjectFile(*File));
+
return Ret;
}
-
-template void BitcodeCompiler::template add<ELF32LE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF32BE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF64LE>(BitcodeFile &);
-template void BitcodeCompiler::template add<ELF64BE>(BitcodeFile &);
diff --git a/ELF/LTO.h b/ELF/LTO.h
index 3cb763650e1c..28afa0e83add 100644
--- a/ELF/LTO.h
+++ b/ELF/LTO.h
@@ -43,12 +43,13 @@ public:
BitcodeCompiler();
~BitcodeCompiler();
- template <class ELFT> void add(BitcodeFile &F);
+ void add(BitcodeFile &F);
std::vector<InputFile *> compile();
private:
std::unique_ptr<llvm::lto::LTO> LTOObj;
std::vector<SmallString<0>> Buff;
+ std::vector<std::unique_ptr<MemoryBuffer>> Files;
};
}
}
diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp
index 3cc235386b88..ab2ca22e9e17 100644
--- a/ELF/LinkerScript.cpp
+++ b/ELF/LinkerScript.cpp
@@ -13,27 +13,21 @@
#include "LinkerScript.h"
#include "Config.h"
-#include "Driver.h"
#include "InputSection.h"
#include "Memory.h"
#include "OutputSections.h"
-#include "ScriptParser.h"
#include "Strings.h"
#include "SymbolTable.h"
#include "Symbols.h"
#include "SyntheticSections.h"
-#include "Target.h"
#include "Writer.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include <algorithm>
#include <cassert>
@@ -41,9 +35,7 @@
#include <cstdint>
#include <iterator>
#include <limits>
-#include <memory>
#include <string>
-#include <tuple>
#include <vector>
using namespace llvm;
@@ -53,77 +45,145 @@ using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-LinkerScriptBase *elf::ScriptBase;
-ScriptConfiguration *elf::ScriptConfig;
+LinkerScript *elf::Script;
+
+uint64_t ExprValue::getValue() const {
+ if (Sec)
+ return Sec->getOffset(Val) + Sec->getOutputSection()->Addr;
+ return Val;
+}
+
+uint64_t ExprValue::getSecAddr() const {
+ if (Sec)
+ return Sec->getOffset(0) + Sec->getOutputSection()->Addr;
+ return 0;
+}
template <class ELFT> static SymbolBody *addRegular(SymbolAssignment *Cmd) {
+ Symbol *Sym;
uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- Symbol *Sym = Symtab<ELFT>::X->addUndefined(
- Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-
- replaceBody<DefinedRegular<ELFT>>(Sym, Cmd->Name, /*IsLocal=*/false,
- Visibility, STT_NOTYPE, 0, 0, nullptr,
- nullptr);
+ std::tie(Sym, std::ignore) = Symtab<ELFT>::X->insert(
+ Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false,
+ /*File*/ nullptr);
+ Sym->Binding = STB_GLOBAL;
+ ExprValue Value = Cmd->Expression();
+ SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec;
+
+ // We want to set symbol values early if we can. This allows us to use symbols
+ // as variables in linker scripts. Doing so allows us to write expressions
+ // like this: `alignment = 16; . = ALIGN(., alignment)`
+ uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0;
+ replaceBody<DefinedRegular>(Sym, Cmd->Name, /*IsLocal=*/false, Visibility,
+ STT_NOTYPE, SymValue, 0, Sec, nullptr);
return Sym->body();
}
-template <class ELFT> static SymbolBody *addSynthetic(SymbolAssignment *Cmd) {
- uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT;
- const OutputSectionBase *Sec =
- ScriptConfig->HasSections ? nullptr : Cmd->Expression.Section();
- Symbol *Sym = Symtab<ELFT>::X->addUndefined(
- Cmd->Name, /*IsLocal=*/false, STB_GLOBAL, Visibility,
- /*Type*/ 0,
- /*CanOmitFromDynSym*/ false, /*File*/ nullptr);
-
- replaceBody<DefinedSynthetic>(Sym, Cmd->Name, 0, Sec);
- return Sym->body();
+OutputSection *LinkerScript::getOutputSection(const Twine &Loc,
+ StringRef Name) {
+ for (OutputSection *Sec : *OutputSections)
+ if (Sec->Name == Name)
+ return Sec;
+
+ static OutputSection Dummy("", 0, 0);
+ if (ErrorOnMissingSection)
+ error(Loc + ": undefined section " + Name);
+ return &Dummy;
}
-static bool isUnderSysroot(StringRef Path) {
- if (Config->Sysroot == "")
- return false;
- for (; !Path.empty(); Path = sys::path::parent_path(Path))
- if (sys::fs::equivalent(Config->Sysroot, Path))
- return true;
- return false;
+// This function is essentially the same as getOutputSection(Name)->Size,
+// but it won't print out an error message if a given section is not found.
+//
+// Linker script does not create an output section if its content is empty.
+// We want to allow SIZEOF(.foo) where .foo is a section which happened to
+// be empty. That is why this function is different from getOutputSection().
+uint64_t LinkerScript::getOutputSectionSize(StringRef Name) {
+ for (OutputSection *Sec : *OutputSections)
+ if (Sec->Name == Name)
+ return Sec->Size;
+ return 0;
+}
+
+void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) {
+ uint64_t Val = E().getValue();
+ if (Val < Dot) {
+ if (InSec)
+ error(Loc + ": unable to move location counter backward for: " +
+ CurOutSec->Name);
+ else
+ error(Loc + ": unable to move location counter backward");
+ }
+ Dot = Val;
+ // Update to location counter means update to section size.
+ if (InSec)
+ CurOutSec->Size = Dot - CurOutSec->Addr;
}
-template <class ELFT> static void assignSymbol(SymbolAssignment *Cmd) {
- // If there are sections, then let the value be assigned later in
- // `assignAddresses`.
- if (ScriptConfig->HasSections)
+// Sets value of a symbol. Two kinds of symbols are processed: synthetic
+// symbols, whose value is an offset from beginning of section and regular
+// symbols whose value is absolute.
+void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) {
+ if (Cmd->Name == ".") {
+ setDot(Cmd->Expression, Cmd->Location, InSec);
+ return;
+ }
+
+ if (!Cmd->Sym)
return;
- uint64_t Value = Cmd->Expression(0);
- if (Cmd->Expression.IsAbsolute()) {
- cast<DefinedRegular<ELFT>>(Cmd->Sym)->Value = Value;
+ auto *Sym = cast<DefinedRegular>(Cmd->Sym);
+ ExprValue V = Cmd->Expression();
+ if (V.isAbsolute()) {
+ Sym->Value = V.getValue();
} else {
- const OutputSectionBase *Sec = Cmd->Expression.Section();
- if (Sec)
- cast<DefinedSynthetic>(Cmd->Sym)->Value = Value - Sec->Addr;
+ Sym->Section = V.Sec;
+ if (Sym->Section->Flags & SHF_ALLOC)
+ Sym->Value = V.Val;
+ else
+ Sym->Value = V.getValue();
+ }
+}
+
+static SymbolBody *findSymbol(StringRef S) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return Symtab<ELF32LE>::X->find(S);
+ case ELF32BEKind:
+ return Symtab<ELF32BE>::X->find(S);
+ case ELF64LEKind:
+ return Symtab<ELF64LE>::X->find(S);
+ case ELF64BEKind:
+ return Symtab<ELF64BE>::X->find(S);
+ default:
+ llvm_unreachable("unknown Config->EKind");
}
}
-template <class ELFT> static void addSymbol(SymbolAssignment *Cmd) {
+static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) {
+ switch (Config->EKind) {
+ case ELF32LEKind:
+ return addRegular<ELF32LE>(Cmd);
+ case ELF32BEKind:
+ return addRegular<ELF32BE>(Cmd);
+ case ELF64LEKind:
+ return addRegular<ELF64LE>(Cmd);
+ case ELF64BEKind:
+ return addRegular<ELF64BE>(Cmd);
+ default:
+ llvm_unreachable("unknown Config->EKind");
+ }
+}
+
+void LinkerScript::addSymbol(SymbolAssignment *Cmd) {
if (Cmd->Name == ".")
return;
// If a symbol was in PROVIDE(), we need to define it only when
// it is a referenced undefined symbol.
- SymbolBody *B = Symtab<ELFT>::X->find(Cmd->Name);
+ SymbolBody *B = findSymbol(Cmd->Name);
if (Cmd->Provide && (!B || B->isDefined()))
return;
- // Otherwise, create a new symbol if one does not exist or an
- // undefined one does exist.
- if (Cmd->Expression.IsAbsolute())
- Cmd->Sym = addRegular<ELFT>(Cmd);
- else
- Cmd->Sym = addSynthetic<ELFT>(Cmd);
- assignSymbol<ELFT>(Cmd);
+ Cmd->Sym = addRegularSymbol(Cmd);
}
bool SymbolAssignment::classof(const BaseCommand *C) {
@@ -146,17 +206,13 @@ bool BytesDataCommand::classof(const BaseCommand *C) {
return C->Kind == BytesDataKind;
}
-template <class ELFT> LinkerScript<ELFT>::LinkerScript() = default;
-template <class ELFT> LinkerScript<ELFT>::~LinkerScript() = default;
-
-template <class ELFT> static StringRef basename(InputSectionBase<ELFT> *S) {
- if (S->getFile())
- return sys::path::filename(S->getFile()->getName());
+static StringRef basename(InputSectionBase *S) {
+ if (S->File)
+ return sys::path::filename(S->File->getName());
return "";
}
-template <class ELFT>
-bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
+bool LinkerScript::shouldKeep(InputSectionBase *S) {
for (InputSectionDescription *ID : Opt.KeptSections)
if (ID->FilePat.match(basename(S)))
for (SectionPattern &P : ID->SectionPatterns)
@@ -165,73 +221,77 @@ bool LinkerScript<ELFT>::shouldKeep(InputSectionBase<ELFT> *S) {
return false;
}
-static bool comparePriority(InputSectionData *A, InputSectionData *B) {
- return getPriority(A->Name) < getPriority(B->Name);
-}
-
-static bool compareName(InputSectionData *A, InputSectionData *B) {
- return A->Name < B->Name;
-}
-
-static bool compareAlignment(InputSectionData *A, InputSectionData *B) {
- // ">" is not a mistake. Larger alignments are placed before smaller
- // alignments in order to reduce the amount of padding necessary.
- // This is compatible with GNU.
- return A->Alignment > B->Alignment;
-}
-
-static std::function<bool(InputSectionData *, InputSectionData *)>
+// A helper function for the SORT() command.
+static std::function<bool(InputSectionBase *, InputSectionBase *)>
getComparator(SortSectionPolicy K) {
switch (K) {
case SortSectionPolicy::Alignment:
- return compareAlignment;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ // ">" is not a mistake. Sections with larger alignments are placed
+ // before sections with smaller alignments in order to reduce the
+ // amount of padding necessary. This is compatible with GNU.
+ return A->Alignment > B->Alignment;
+ };
case SortSectionPolicy::Name:
- return compareName;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return A->Name < B->Name;
+ };
case SortSectionPolicy::Priority:
- return comparePriority;
+ return [](InputSectionBase *A, InputSectionBase *B) {
+ return getPriority(A->Name) < getPriority(B->Name);
+ };
default:
llvm_unreachable("unknown sort policy");
}
}
-template <class ELFT>
-static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
+// A helper function for the SORT() command.
+static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,
ConstraintKind Kind) {
if (Kind == ConstraintKind::NoConstraint)
return true;
- bool IsRW = llvm::any_of(Sections, [=](InputSectionData *Sec2) {
- auto *Sec = static_cast<InputSectionBase<ELFT> *>(Sec2);
- return Sec->Flags & SHF_WRITE;
+
+ bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) {
+ return static_cast<InputSectionBase *>(Sec)->Flags & SHF_WRITE;
});
+
return (IsRW && Kind == ConstraintKind::ReadWrite) ||
(!IsRW && Kind == ConstraintKind::ReadOnly);
}
-static void sortSections(InputSectionData **Begin, InputSectionData **End,
+static void sortSections(InputSectionBase **Begin, InputSectionBase **End,
SortSectionPolicy K) {
if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)
std::stable_sort(Begin, End, getComparator(K));
}
// Compute and remember which sections the InputSectionDescription matches.
-template <class ELFT>
-void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
- // Collects all sections that satisfy constraints of I
- // and attach them to I.
- for (SectionPattern &Pat : I->SectionPatterns) {
- size_t SizeBefore = I->Sections.size();
-
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) {
- if (!S->Live || S->Assigned)
+std::vector<InputSectionBase *>
+LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {
+ std::vector<InputSectionBase *> Ret;
+
+ // Collects all sections that satisfy constraints of Cmd.
+ for (const SectionPattern &Pat : Cmd->SectionPatterns) {
+ size_t SizeBefore = Ret.size();
+
+ for (InputSectionBase *Sec : InputSections) {
+ if (Sec->Assigned)
continue;
- StringRef Filename = basename(S);
- if (!I->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename))
+ // For -emit-relocs we have to ignore entries like
+ // .rela.dyn : { *(.rela.data) }
+ // which are common because they are in the default bfd script.
+ if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA)
continue;
- if (!Pat.SectionPat.match(S->Name))
+
+ StringRef Filename = basename(Sec);
+ if (!Cmd->FilePat.match(Filename) ||
+ Pat.ExcludedFilePat.match(Filename) ||
+ !Pat.SectionPat.match(Sec->Name))
continue;
- I->Sections.push_back(S);
- S->Assigned = true;
+
+ Ret.push_back(Sec);
+ Sec->Assigned = true;
}
// Sort sections as instructed by SORT-family commands and --sort-section
@@ -245,8 +305,8 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
// --sort-section is handled as an inner SORT command.
// 3. If one SORT command is given, and if it is SORT_NONE, don't sort.
// 4. If no SORT command is given, sort according to --sort-section.
- InputSectionData **Begin = I->Sections.data() + SizeBefore;
- InputSectionData **End = I->Sections.data() + I->Sections.size();
+ InputSectionBase **Begin = Ret.data() + SizeBefore;
+ InputSectionBase **End = Ret.data() + Ret.size();
if (Pat.SortOuter != SortSectionPolicy::None) {
if (Pat.SortInner == SortSectionPolicy::Default)
sortSections(Begin, End, Config->SortSection);
@@ -255,68 +315,58 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
sortSections(Begin, End, Pat.SortOuter);
}
}
+ return Ret;
}
-template <class ELFT>
-void LinkerScript<ELFT>::discard(ArrayRef<InputSectionBase<ELFT> *> V) {
- for (InputSectionBase<ELFT> *S : V) {
+void LinkerScript::discard(ArrayRef<InputSectionBase *> V) {
+ for (InputSectionBase *S : V) {
S->Live = false;
- reportDiscarded(S);
+ if (S == InX::ShStrTab)
+ error("discarding .shstrtab section is not allowed");
+ discard(S->DependentSections);
}
}
-template <class ELFT>
-std::vector<InputSectionBase<ELFT> *>
-LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) {
- std::vector<InputSectionBase<ELFT> *> Ret;
+std::vector<InputSectionBase *>
+LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) {
+ std::vector<InputSectionBase *> Ret;
- for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) {
- auto *Cmd = dyn_cast<InputSectionDescription>(Base.get());
+ for (BaseCommand *Base : OutCmd.Commands) {
+ auto *Cmd = dyn_cast<InputSectionDescription>(Base);
if (!Cmd)
continue;
- computeInputSections(Cmd);
- for (InputSectionData *S : Cmd->Sections)
- Ret.push_back(static_cast<InputSectionBase<ELFT> *>(S));
+
+ Cmd->Sections = computeInputSections(Cmd);
+ Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end());
}
return Ret;
}
-template <class ELFT>
-void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
- InputSectionBase<ELFT> *Sec,
- StringRef Name) {
- OutputSectionBase *OutSec;
- bool IsNew;
- std::tie(OutSec, IsNew) = Factory.create(Sec, Name);
- if (IsNew)
- OutputSections->push_back(OutSec);
- OutSec->addSection(Sec);
-}
-
-template <class ELFT>
-void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) {
- for (unsigned I = 0; I < Opt.Commands.size(); ++I) {
- auto Iter = Opt.Commands.begin() + I;
- const std::unique_ptr<BaseCommand> &Base1 = *Iter;
+void LinkerScript::processCommands(OutputSectionFactory &Factory) {
+ // A symbol can be assigned before any section is mentioned in the linker
+ // script. In an DSO, the symbol values are addresses, so the only important
+ // section values are:
+ // * SHN_UNDEF
+ // * SHN_ABS
+ // * Any value meaning a regular section.
+ // To handle that, create a dummy aether section that fills the void before
+ // the linker scripts switches to another section. It has an index of one
+ // which will map to whatever the first actual section is.
+ Aether = make<OutputSection>("", 0, SHF_ALLOC);
+ Aether->SectionIndex = 1;
+ CurOutSec = Aether;
+ Dot = 0;
+ for (size_t I = 0; I < Opt.Commands.size(); ++I) {
// Handle symbol assignments outside of any output section.
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base1.get())) {
- addSymbol<ELFT>(Cmd);
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Opt.Commands[I])) {
+ addSymbol(Cmd);
continue;
}
- if (auto *Cmd = dyn_cast<AssertCommand>(Base1.get())) {
- // If we don't have SECTIONS then output sections have already been
- // created by Writer<ELFT>. The LinkerScript<ELFT>::assignAddresses
- // will not be called, so ASSERT should be evaluated now.
- if (!Opt.HasSections)
- Cmd->Expression(0);
- continue;
- }
-
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base1.get())) {
- std::vector<InputSectionBase<ELFT> *> V = createInputSectionList(*Cmd);
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I])) {
+ std::vector<InputSectionBase *> V = createInputSectionList(*Cmd);
// The output section name `/DISCARD/' is special.
// Any input section assigned to it is discarded.
@@ -332,74 +382,54 @@ void LinkerScript<ELFT>::processCommands(OutputSectionFactory<ELFT> &Factory) {
//
// Because we'll iterate over Commands many more times, the easiest
// way to "make it as if it wasn't present" is to just remove it.
- if (!matchConstraints<ELFT>(V, Cmd->Constraint)) {
- for (InputSectionBase<ELFT> *S : V)
+ if (!matchConstraints(V, Cmd->Constraint)) {
+ for (InputSectionBase *S : V)
S->Assigned = false;
- Opt.Commands.erase(Iter);
+ Opt.Commands.erase(Opt.Commands.begin() + I);
--I;
continue;
}
// A directive may contain symbol definitions like this:
// ".foo : { ...; bar = .; }". Handle them.
- for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
- if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get()))
- addSymbol<ELFT>(OutCmd);
+ for (BaseCommand *Base : Cmd->Commands)
+ if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base))
+ addSymbol(OutCmd);
// Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign
// is given, input sections are aligned to that value, whether the
// given value is larger or smaller than the original section alignment.
if (Cmd->SubalignExpr) {
- uint32_t Subalign = Cmd->SubalignExpr(0);
- for (InputSectionBase<ELFT> *S : V)
+ uint32_t Subalign = Cmd->SubalignExpr().getValue();
+ for (InputSectionBase *S : V)
S->Alignment = Subalign;
}
// Add input sections to an output section.
- for (InputSectionBase<ELFT> *S : V)
- addSection(Factory, S, Cmd->Name);
+ for (InputSectionBase *S : V)
+ Factory.addInputSec(S, Cmd->Name);
}
}
+ CurOutSec = nullptr;
}
// Add sections that didn't match any sections command.
-template <class ELFT>
-void LinkerScript<ELFT>::addOrphanSections(
- OutputSectionFactory<ELFT> &Factory) {
- for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections)
+void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {
+ for (InputSectionBase *S : InputSections)
if (S->Live && !S->OutSec)
- addSection(Factory, S, getOutputSectionName(S->Name));
+ Factory.addInputSec(S, getOutputSectionName(S->Name));
}
-// Sets value of a section-defined symbol. Two kinds of
-// symbols are processed: synthetic symbols, whose value
-// is an offset from beginning of section and regular
-// symbols whose value is absolute.
-template <class ELFT>
-static void assignSectionSymbol(SymbolAssignment *Cmd,
- typename ELFT::uint Value) {
- if (!Cmd->Sym)
- return;
-
- if (auto *Body = dyn_cast<DefinedSynthetic>(Cmd->Sym)) {
- Body->Section = Cmd->Expression.Section();
- Body->Value = Cmd->Expression(Value) - Body->Section->Addr;
- return;
- }
- auto *Body = cast<DefinedRegular<ELFT>>(Cmd->Sym);
- Body->Value = Cmd->Expression(Value);
-}
-
-template <class ELFT> static bool isTbss(OutputSectionBase *Sec) {
+static bool isTbss(OutputSection *Sec) {
return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS;
}
-template <class ELFT> void LinkerScript<ELFT>::output(InputSection<ELFT> *S) {
+void LinkerScript::output(InputSection *S) {
if (!AlreadyOutputIS.insert(S).second)
return;
- bool IsTbss = isTbss<ELFT>(CurOutSec);
+ bool IsTbss = isTbss(CurOutSec);
- uintX_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
+ uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot;
Pos = alignTo(Pos, S->Alignment);
S->OutSecOff = Pos - CurOutSec->Addr;
Pos += S->getSize();
@@ -409,134 +439,171 @@ template <class ELFT> void LinkerScript<ELFT>::output(InputSection<ELFT> *S) {
// .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) }
CurOutSec->Size = Pos - CurOutSec->Addr;
+ // If there is a memory region associated with this input section, then
+ // place the section in that region and update the region index.
+ if (CurMemRegion) {
+ CurMemRegion->Offset += CurOutSec->Size;
+ uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin;
+ if (CurSize > CurMemRegion->Length) {
+ uint64_t OverflowAmt = CurSize - CurMemRegion->Length;
+ error("section '" + CurOutSec->Name + "' will not fit in region '" +
+ CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) +
+ " bytes");
+ }
+ }
+
if (IsTbss)
ThreadBssOffset = Pos - Dot;
else
Dot = Pos;
}
-template <class ELFT> void LinkerScript<ELFT>::flush() {
- if (!CurOutSec || !AlreadyOutputOS.insert(CurOutSec).second)
+void LinkerScript::flush() {
+ assert(CurOutSec);
+ if (!AlreadyOutputOS.insert(CurOutSec).second)
return;
- if (auto *OutSec = dyn_cast<OutputSection<ELFT>>(CurOutSec)) {
- for (InputSection<ELFT> *I : OutSec->Sections)
- output(I);
- } else {
- Dot += CurOutSec->Size;
- }
+ for (InputSection *I : CurOutSec->Sections)
+ output(I);
}
-template <class ELFT>
-void LinkerScript<ELFT>::switchTo(OutputSectionBase *Sec) {
+void LinkerScript::switchTo(OutputSection *Sec) {
if (CurOutSec == Sec)
return;
if (AlreadyOutputOS.count(Sec))
return;
- flush();
CurOutSec = Sec;
- Dot = alignTo(Dot, CurOutSec->Addralign);
- CurOutSec->Addr = isTbss<ELFT>(CurOutSec) ? Dot + ThreadBssOffset : Dot;
+ Dot = alignTo(Dot, CurOutSec->Alignment);
+ CurOutSec->Addr = isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot;
// If neither AT nor AT> is specified for an allocatable section, the linker
// will set the LMA such that the difference between VMA and LMA for the
// section is the same as the preceding output section in the same region
// https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html
- CurOutSec->setLMAOffset(LMAOffset);
+ if (LMAOffset)
+ CurOutSec->LMAOffset = LMAOffset();
}
-template <class ELFT> void LinkerScript<ELFT>::process(BaseCommand &Base) {
- // This handles the assignments to symbol or to a location counter (.)
- if (auto *AssignCmd = dyn_cast<SymbolAssignment>(&Base)) {
- if (AssignCmd->Name == ".") {
- // Update to location counter means update to section size.
- uintX_t Val = AssignCmd->Expression(Dot);
- if (Val < Dot)
- error("unable to move location counter backward for: " +
- CurOutSec->Name);
- Dot = Val;
- CurOutSec->Size = Dot - CurOutSec->Addr;
- return;
- }
- assignSectionSymbol<ELFT>(AssignCmd, Dot);
+void LinkerScript::process(BaseCommand &Base) {
+ // This handles the assignments to symbol or to the dot.
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(&Base)) {
+ assignSymbol(Cmd, true);
return;
}
// Handle BYTE(), SHORT(), LONG(), or QUAD().
- if (auto *DataCmd = dyn_cast<BytesDataCommand>(&Base)) {
- DataCmd->Offset = Dot - CurOutSec->Addr;
- Dot += DataCmd->Size;
+ if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) {
+ Cmd->Offset = Dot - CurOutSec->Addr;
+ Dot += Cmd->Size;
CurOutSec->Size = Dot - CurOutSec->Addr;
return;
}
- if (auto *AssertCmd = dyn_cast<AssertCommand>(&Base)) {
- AssertCmd->Expression(Dot);
+ // Handle ASSERT().
+ if (auto *Cmd = dyn_cast<AssertCommand>(&Base)) {
+ Cmd->Expression();
return;
}
- // It handles single input section description command,
- // calculates and assigns the offsets for each section and also
+ // Handle a single input section description command.
+ // It calculates and assigns the offsets for each section and also
// updates the output section size.
- auto &ICmd = cast<InputSectionDescription>(Base);
- for (InputSectionData *ID : ICmd.Sections) {
+ auto &Cmd = cast<InputSectionDescription>(Base);
+ for (InputSectionBase *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 *Sec = dyn_cast<SyntheticSection<ELFT>>(ID))
- if (Sec->empty())
+ if (auto *S = dyn_cast<SyntheticSection>(Sec))
+ if (S->empty())
continue;
- auto *IB = static_cast<InputSectionBase<ELFT> *>(ID);
- switchTo(IB->OutSec);
- if (auto *I = dyn_cast<InputSection<ELFT>>(IB))
- output(I);
- else
- flush();
+ if (!Sec->Live)
+ continue;
+ assert(CurOutSec == Sec->OutSec || AlreadyOutputOS.count(Sec->OutSec));
+ output(cast<InputSection>(Sec));
}
}
-template <class ELFT>
-static std::vector<OutputSectionBase *>
-findSections(StringRef Name, const std::vector<OutputSectionBase *> &Sections) {
- std::vector<OutputSectionBase *> Ret;
- for (OutputSectionBase *Sec : Sections)
- if (Sec->getName() == Name)
- Ret.push_back(Sec);
- return Ret;
+static OutputSection *
+findSection(StringRef Name, const std::vector<OutputSection *> &Sections) {
+ for (OutputSection *Sec : Sections)
+ if (Sec->Name == Name)
+ return Sec;
+ return nullptr;
+}
+
+// This function searches for a memory region to place the given output
+// section in. If found, a pointer to the appropriate memory region is
+// returned. Otherwise, a nullptr is returned.
+MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) {
+ // If a memory region name was specified in the output section command,
+ // then try to find that region first.
+ if (!Cmd->MemoryRegionName.empty()) {
+ auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName);
+ if (It != Opt.MemoryRegions.end())
+ return &It->second;
+ error("memory region '" + Cmd->MemoryRegionName + "' not declared");
+ return nullptr;
+ }
+
+ // If at least one memory region is defined, all sections must
+ // belong to some memory region. Otherwise, we don't need to do
+ // anything for memory regions.
+ if (Opt.MemoryRegions.empty())
+ return nullptr;
+
+ OutputSection *Sec = Cmd->Sec;
+ // See if a region can be found by matching section flags.
+ for (auto &Pair : Opt.MemoryRegions) {
+ MemoryRegion &M = Pair.second;
+ if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0)
+ return &M;
+ }
+
+ // Otherwise, no suitable region was found.
+ if (Sec->Flags & SHF_ALLOC)
+ error("no memory region specified for section '" + Sec->Name + "'");
+ return nullptr;
}
// This function assigns offsets to input sections and an output section
// for a single sections command (e.g. ".text { *(.text); }").
-template <class ELFT>
-void LinkerScript<ELFT>::assignOffsets(OutputSectionCommand *Cmd) {
- if (Cmd->LMAExpr)
- LMAOffset = Cmd->LMAExpr(Dot) - Dot;
- std::vector<OutputSectionBase *> Sections =
- findSections<ELFT>(Cmd->Name, *OutputSections);
- if (Sections.empty())
+void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) {
+ OutputSection *Sec = Cmd->Sec;
+ if (!Sec)
return;
- switchTo(Sections[0]);
-
- // Find the last section output location. We will output orphan sections
- // there so that end symbols point to the correct location.
- auto E = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
- [](const std::unique_ptr<BaseCommand> &Cmd) {
- return !isa<SymbolAssignment>(*Cmd);
- })
- .base();
- for (auto I = Cmd->Commands.begin(); I != E; ++I)
+
+ if (Cmd->AddrExpr && (Sec->Flags & SHF_ALLOC))
+ setDot(Cmd->AddrExpr, Cmd->Location, false);
+
+ if (Cmd->LMAExpr) {
+ uint64_t D = Dot;
+ LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; };
+ }
+
+ CurMemRegion = Cmd->MemRegion;
+ if (CurMemRegion)
+ Dot = CurMemRegion->Offset;
+ switchTo(Sec);
+
+ // flush() may add orphan sections, so the order of flush() and
+ // symbol assignments is important. We want to call flush() first so
+ // that symbols pointing the end of the current section points to
+ // the location after orphan sections.
+ auto Mid =
+ std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(),
+ [](BaseCommand *Cmd) { return !isa<SymbolAssignment>(Cmd); })
+ .base();
+ for (auto I = Cmd->Commands.begin(); I != Mid; ++I)
process(**I);
- for (OutputSectionBase *Base : Sections)
- switchTo(Base);
flush();
- std::for_each(E, Cmd->Commands.end(),
- [this](std::unique_ptr<BaseCommand> &B) { process(*B.get()); });
+ for (auto I = Mid, E = Cmd->Commands.end(); I != E; ++I)
+ process(**I);
}
-template <class ELFT> void LinkerScript<ELFT>::removeEmptyCommands() {
+void LinkerScript::removeEmptyCommands() {
// It is common practice to use very generic linker scripts. So for any
// given run some of the output sections in the script will be empty.
// We could create corresponding empty output sections, but that would
@@ -544,52 +611,61 @@ template <class ELFT> void LinkerScript<ELFT>::removeEmptyCommands() {
// We instead remove trivially empty sections. The bfd linker seems even
// more aggressive at removing them.
auto Pos = std::remove_if(
- Opt.Commands.begin(), Opt.Commands.end(),
- [&](const std::unique_ptr<BaseCommand> &Base) {
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
- return findSections<ELFT>(Cmd->Name, *OutputSections).empty();
+ Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
+ return !Cmd->Sec;
return false;
});
Opt.Commands.erase(Pos, Opt.Commands.end());
}
static bool isAllSectionDescription(const OutputSectionCommand &Cmd) {
- for (const std::unique_ptr<BaseCommand> &I : Cmd.Commands)
- if (!isa<InputSectionDescription>(*I))
+ for (BaseCommand *Base : Cmd.Commands)
+ if (!isa<InputSectionDescription>(*Base))
return false;
return true;
}
-template <class ELFT> void LinkerScript<ELFT>::adjustSectionsBeforeSorting() {
+void LinkerScript::adjustSectionsBeforeSorting() {
// If the output section contains only symbol assignments, create a
// corresponding output section. The bfd linker seems to only create them if
// '.' is assigned to, but creating these section should not have any bad
// consequeces and gives us a section to put the symbol in.
- uintX_t Flags = SHF_ALLOC;
- uint32_t Type = SHT_NOBITS;
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ uint64_t Flags = SHF_ALLOC;
+ uint32_t Type = SHT_PROGBITS;
+ for (BaseCommand *Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
- std::vector<OutputSectionBase *> Secs =
- findSections<ELFT>(Cmd->Name, *OutputSections);
- if (!Secs.empty()) {
- Flags = Secs[0]->Flags;
- Type = Secs[0]->Type;
+ if (OutputSection *Sec = findSection(Cmd->Name, *OutputSections)) {
+ Cmd->Sec = Sec;
+ Flags = Sec->Flags;
+ Type = Sec->Type;
continue;
}
if (isAllSectionDescription(*Cmd))
continue;
- auto *OutSec = make<OutputSection<ELFT>>(Cmd->Name, Type, Flags);
+ auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags);
OutputSections->push_back(OutSec);
+ Cmd->Sec = OutSec;
}
}
-template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
+void LinkerScript::adjustSectionsAfterSorting() {
placeOrphanSections();
+ // Try and find an appropriate memory region to assign offsets in.
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) {
+ Cmd->MemRegion = findMemoryRegion(Cmd);
+ // Handle align (e.g. ".foo : ALIGN(16) { ... }").
+ if (Cmd->AlignExpr)
+ Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue());
+ }
+ }
+
// If output section command doesn't specify any segments,
// and we haven't previously assigned any section to segment,
// then we simply assign section to the very first load segment.
@@ -605,10 +681,11 @@ template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+ for (BaseCommand *Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd)
continue;
+
if (Cmd->Phdrs.empty())
Cmd->Phdrs = DefPhdrs;
else
@@ -632,19 +709,37 @@ template <class ELFT> void LinkerScript<ELFT>::adjustSectionsAfterSorting() {
// /* The RW PT_LOAD starts here*/
// rw_sec : { *(rw_sec) }
// would mean that the RW PT_LOAD would become unaligned.
-static bool shouldSkip(const BaseCommand &Cmd) {
+static bool shouldSkip(BaseCommand *Cmd) {
if (isa<OutputSectionCommand>(Cmd))
return false;
- const auto *Assign = dyn_cast<SymbolAssignment>(&Cmd);
- if (!Assign)
- return true;
- return Assign->Name != ".";
+ if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd))
+ return Assign->Name != ".";
+ return true;
}
-// Orphan sections are sections present in the input files which are not
-// explicitly placed into the output file by the linker script. This just
-// places them in the order already decided in OutputSections.
-template <class ELFT> void LinkerScript<ELFT>::placeOrphanSections() {
+// Orphan sections are sections present in the input files which are
+// not explicitly placed into the output file by the linker script.
+//
+// When the control reaches this function, Opt.Commands contains
+// output section commands for non-orphan sections only. This function
+// adds new elements for orphan sections so that all sections are
+// explicitly handled by Opt.Commands.
+//
+// Writer<ELFT>::sortSections has already sorted output sections.
+// What we need to do is to scan OutputSections vector and
+// Opt.Commands in parallel to find orphan sections. If there is an
+// output section that doesn't have a corresponding entry in
+// Opt.Commands, we will insert a new entry to Opt.Commands.
+//
+// There is some ambiguity as to where exactly a new entry should be
+// inserted, because Opt.Commands contains not only output section
+// commands but also other types of commands such as symbol assignment
+// expressions. There's no correct answer here due to the lack of the
+// formal specification of the linker script. We use heuristics to
+// determine whether a new output command should be added before or
+// after another commands. For the details, look at shouldSkip
+// function.
+void LinkerScript::placeOrphanSections() {
// The OutputSections are already in the correct order.
// This loops creates or moves commands as needed so that they are in the
// correct order.
@@ -656,40 +751,33 @@ template <class ELFT> void LinkerScript<ELFT>::placeOrphanSections() {
// after that.
auto FirstSectionOrDotAssignment =
std::find_if(Opt.Commands.begin(), Opt.Commands.end(),
- [](const std::unique_ptr<BaseCommand> &Cmd) {
- if (isa<OutputSectionCommand>(*Cmd))
- return true;
- const auto *Assign = dyn_cast<SymbolAssignment>(Cmd.get());
- if (!Assign)
- return false;
- return Assign->Name == ".";
- });
+ [](BaseCommand *Cmd) { return !shouldSkip(Cmd); });
if (FirstSectionOrDotAssignment != Opt.Commands.end()) {
CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin();
if (isa<SymbolAssignment>(**FirstSectionOrDotAssignment))
++CmdIndex;
}
- for (OutputSectionBase *Sec : *OutputSections) {
- StringRef Name = Sec->getName();
+ for (OutputSection *Sec : *OutputSections) {
+ StringRef Name = Sec->Name;
// Find the last spot where we can insert a command and still get the
// correct result.
auto CmdIter = Opt.Commands.begin() + CmdIndex;
auto E = Opt.Commands.end();
- while (CmdIter != E && shouldSkip(**CmdIter)) {
+ while (CmdIter != E && shouldSkip(*CmdIter)) {
++CmdIter;
++CmdIndex;
}
- auto Pos =
- std::find_if(CmdIter, E, [&](const std::unique_ptr<BaseCommand> &Base) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
- return Cmd && Cmd->Name == Name;
- });
+ auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
+ return Cmd && Cmd->Name == Name;
+ });
if (Pos == E) {
- Opt.Commands.insert(CmdIter,
- llvm::make_unique<OutputSectionCommand>(Name));
+ auto *Cmd = make<OutputSectionCommand>(Name);
+ Cmd->Sec = Sec;
+ Opt.Commands.insert(CmdIter, Cmd);
++CmdIndex;
continue;
}
@@ -699,55 +787,49 @@ template <class ELFT> void LinkerScript<ELFT>::placeOrphanSections() {
}
}
-template <class ELFT>
-void LinkerScript<ELFT>::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
+void LinkerScript::processNonSectionCommands() {
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base))
+ assignSymbol(Cmd, false);
+ else if (auto *Cmd = dyn_cast<AssertCommand>(Base))
+ Cmd->Expression();
+ }
+}
+
+void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) {
// Assign addresses as instructed by linker script SECTIONS sub-commands.
Dot = 0;
+ ErrorOnMissingSection = true;
+ switchTo(Aether);
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
- if (Cmd->Name == ".") {
- Dot = Cmd->Expression(Dot);
- } else if (Cmd->Sym) {
- assignSectionSymbol<ELFT>(Cmd, Dot);
- }
+ for (BaseCommand *Base : Opt.Commands) {
+ if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
+ assignSymbol(Cmd, false);
continue;
}
- if (auto *Cmd = dyn_cast<AssertCommand>(Base.get())) {
- Cmd->Expression(Dot);
+ if (auto *Cmd = dyn_cast<AssertCommand>(Base)) {
+ Cmd->Expression();
continue;
}
- auto *Cmd = cast<OutputSectionCommand>(Base.get());
- if (Cmd->AddrExpr)
- Dot = Cmd->AddrExpr(Dot);
+ auto *Cmd = cast<OutputSectionCommand>(Base);
assignOffsets(Cmd);
}
- uintX_t MinVA = std::numeric_limits<uintX_t>::max();
- for (OutputSectionBase *Sec : *OutputSections) {
+ uint64_t MinVA = std::numeric_limits<uint64_t>::max();
+ for (OutputSection *Sec : *OutputSections) {
if (Sec->Flags & SHF_ALLOC)
MinVA = std::min<uint64_t>(MinVA, Sec->Addr);
else
Sec->Addr = 0;
}
- uintX_t HeaderSize = getHeaderSize();
- // If the linker script doesn't have PHDRS, add ElfHeader and ProgramHeaders
- // now that we know we have space.
- if (HeaderSize <= MinVA && !hasPhdrsCommands())
- allocateHeaders<ELFT>(Phdrs, *OutputSections);
-
- // ELF and Program headers need to be right before the first section in
- // memory. Set their addresses accordingly.
- MinVA = alignDown(MinVA - HeaderSize, Config->MaxPageSize);
- Out<ELFT>::ElfHeader->Addr = MinVA;
- Out<ELFT>::ProgramHeaders->Addr = Out<ELFT>::ElfHeader->Size + MinVA;
+ allocateHeaders(Phdrs, *OutputSections, MinVA);
}
// Creates program headers as instructed by PHDRS linker script command.
-template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
+std::vector<PhdrEntry> LinkerScript::createPhdrs() {
std::vector<PhdrEntry> Ret;
// Process PHDRS and FILEHDR keywords because they are not
@@ -757,23 +839,23 @@ template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
PhdrEntry &Phdr = Ret.back();
if (Cmd.HasFilehdr)
- Phdr.add(Out<ELFT>::ElfHeader);
+ Phdr.add(Out::ElfHeader);
if (Cmd.HasPhdrs)
- Phdr.add(Out<ELFT>::ProgramHeaders);
+ Phdr.add(Out::ProgramHeaders);
if (Cmd.LMAExpr) {
- Phdr.p_paddr = Cmd.LMAExpr(0);
+ Phdr.p_paddr = Cmd.LMAExpr().getValue();
Phdr.HasLMA = true;
}
}
// Add output sections to program headers.
- for (OutputSectionBase *Sec : *OutputSections) {
+ for (OutputSection *Sec : *OutputSections) {
if (!(Sec->Flags & SHF_ALLOC))
break;
// Assign headers specified by linker script
- for (size_t Id : getPhdrIndices(Sec->getName())) {
+ for (size_t Id : getPhdrIndices(Sec->Name)) {
Ret[Id].add(Sec);
if (Opt.PhdrsCommands[Id].Flags == UINT_MAX)
Ret[Id].p_flags |= Sec->getPhdrFlags();
@@ -782,60 +864,52 @@ template <class ELFT> std::vector<PhdrEntry> LinkerScript<ELFT>::createPhdrs() {
return Ret;
}
-template <class ELFT> bool LinkerScript<ELFT>::ignoreInterpSection() {
+bool LinkerScript::ignoreInterpSection() {
// Ignore .interp section in case we have PHDRS specification
// and PT_INTERP isn't listed.
- return !Opt.PhdrsCommands.empty() &&
- llvm::find_if(Opt.PhdrsCommands, [](const PhdrsCommand &Cmd) {
- return Cmd.Type == PT_INTERP;
- }) == Opt.PhdrsCommands.end();
+ if (Opt.PhdrsCommands.empty())
+ return false;
+ for (PhdrsCommand &Cmd : Opt.PhdrsCommands)
+ if (Cmd.Type == PT_INTERP)
+ return false;
+ return true;
}
-template <class ELFT> uint32_t LinkerScript<ELFT>::getFiller(StringRef Name) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+Optional<uint32_t> LinkerScript::getFiller(StringRef Name) {
+ for (BaseCommand *Base : Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->Name == Name)
return Cmd->Filler;
- return 0;
+ return None;
}
-template <class ELFT>
static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {
- const endianness E = ELFT::TargetEndianness;
-
- switch (Size) {
- case 1:
- *Buf = (uint8_t)Data;
- break;
- case 2:
- write16<E>(Buf, Data);
- break;
- case 4:
- write32<E>(Buf, Data);
- break;
- case 8:
- write64<E>(Buf, Data);
- break;
- default:
+ if (Size == 1)
+ *Buf = Data;
+ else if (Size == 2)
+ write16(Buf, Data, Config->Endianness);
+ else if (Size == 4)
+ write32(Buf, Data, Config->Endianness);
+ else if (Size == 8)
+ write64(Buf, Data, Config->Endianness);
+ else
llvm_unreachable("unsupported Size argument");
- }
}
-template <class ELFT>
-void LinkerScript<ELFT>::writeDataBytes(StringRef Name, uint8_t *Buf) {
+void LinkerScript::writeDataBytes(StringRef Name, uint8_t *Buf) {
int I = getSectionIndex(Name);
if (I == INT_MAX)
return;
- auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get());
- for (const std::unique_ptr<BaseCommand> &Base : Cmd->Commands)
- if (auto *Data = dyn_cast<BytesDataCommand>(Base.get()))
- writeInt<ELFT>(Buf + Data->Offset, Data->Expression(0), Data->Size);
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]);
+ for (BaseCommand *Base : Cmd->Commands)
+ if (auto *Data = dyn_cast<BytesDataCommand>(Base))
+ writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);
}
-template <class ELFT> bool LinkerScript<ELFT>::hasLMA(StringRef Name) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get()))
+bool LinkerScript::hasLMA(StringRef Name) {
+ for (BaseCommand *Base : Opt.Commands)
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base))
if (Cmd->LMAExpr && Cmd->Name == Name)
return true;
return false;
@@ -845,89 +919,35 @@ template <class ELFT> bool LinkerScript<ELFT>::hasLMA(StringRef Name) {
// SECTIONS commands. Sections are laid out as the same order as they
// were in the script. If a given name did not appear in the script,
// it returns INT_MAX, so that it will be laid out at end of file.
-template <class ELFT> int LinkerScript<ELFT>::getSectionIndex(StringRef Name) {
+int LinkerScript::getSectionIndex(StringRef Name) {
for (int I = 0, E = Opt.Commands.size(); I != E; ++I)
- if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I].get()))
+ if (auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]))
if (Cmd->Name == Name)
return I;
return INT_MAX;
}
-template <class ELFT> bool LinkerScript<ELFT>::hasPhdrsCommands() {
- return !Opt.PhdrsCommands.empty();
-}
-
-template <class ELFT>
-const OutputSectionBase *LinkerScript<ELFT>::getOutputSection(const Twine &Loc,
- StringRef Name) {
- static OutputSectionBase FakeSec("", 0, 0);
-
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec;
-
- error(Loc + ": undefined section " + Name);
- return &FakeSec;
-}
-
-// This function is essentially the same as getOutputSection(Name)->Size,
-// but it won't print out an error message if a given section is not found.
-//
-// Linker script does not create an output section if its content is empty.
-// We want to allow SIZEOF(.foo) where .foo is a section which happened to
-// be empty. That is why this function is different from getOutputSection().
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getOutputSectionSize(StringRef Name) {
- for (OutputSectionBase *Sec : *OutputSections)
- if (Sec->getName() == Name)
- return Sec->Size;
- return 0;
-}
-
-template <class ELFT> uint64_t LinkerScript<ELFT>::getHeaderSize() {
- return elf::getHeaderSize<ELFT>();
-}
-
-template <class ELFT>
-uint64_t LinkerScript<ELFT>::getSymbolValue(const Twine &Loc, StringRef S) {
- if (SymbolBody *B = Symtab<ELFT>::X->find(S))
- return B->getVA<ELFT>();
+ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) {
+ if (S == ".")
+ return {CurOutSec, Dot - CurOutSec->Addr};
+ if (SymbolBody *B = findSymbol(S)) {
+ if (auto *D = dyn_cast<DefinedRegular>(B))
+ return {D->Section, D->Value};
+ if (auto *C = dyn_cast<DefinedCommon>(B))
+ return {InX::Common, C->Offset};
+ }
error(Loc + ": symbol not found: " + S);
return 0;
}
-template <class ELFT> bool LinkerScript<ELFT>::isDefined(StringRef S) {
- return Symtab<ELFT>::X->find(S) != nullptr;
-}
-
-template <class ELFT> bool LinkerScript<ELFT>::isAbsolute(StringRef S) {
- SymbolBody *Sym = Symtab<ELFT>::X->find(S);
- auto *DR = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym);
- return DR && !DR->Section;
-}
-
-// Gets section symbol belongs to. Symbol "." doesn't belong to any
-// specific section but isn't absolute at the same time, so we try
-// to find suitable section for it as well.
-template <class ELFT>
-const OutputSectionBase *LinkerScript<ELFT>::getSymbolSection(StringRef S) {
- SymbolBody *Sym = Symtab<ELFT>::X->find(S);
- if (!Sym) {
- if (OutputSections->empty())
- return nullptr;
- return CurOutSec ? CurOutSec : (*OutputSections)[0];
- }
-
- return SymbolTableSection<ELFT>::getOutputSection(Sym);
-}
+bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; }
// Returns indices of ELF headers containing specific section, identified
// by Name. Each index is a zero based number of ELF header listed within
// PHDRS {} script block.
-template <class ELFT>
-std::vector<size_t> LinkerScript<ELFT>::getPhdrIndices(StringRef SectionName) {
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
+std::vector<size_t> LinkerScript::getPhdrIndices(StringRef SectionName) {
+ for (BaseCommand *Base : Opt.Commands) {
+ auto *Cmd = dyn_cast<OutputSectionCommand>(Base);
if (!Cmd || Cmd->Name != SectionName)
continue;
@@ -939,8 +959,7 @@ std::vector<size_t> LinkerScript<ELFT>::getPhdrIndices(StringRef SectionName) {
return {};
}
-template <class ELFT>
-size_t LinkerScript<ELFT>::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
+size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
size_t I = 0;
for (PhdrsCommand &Cmd : Opt.PhdrsCommands) {
if (Cmd.Name == PhdrName)
@@ -950,1009 +969,3 @@ size_t LinkerScript<ELFT>::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {
error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");
return 0;
}
-
-class elf::ScriptParser final : public ScriptParserBase {
- typedef void (ScriptParser::*Handler)();
-
-public:
- ScriptParser(MemoryBufferRef MB)
- : ScriptParserBase(MB),
- IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
-
- void readLinkerScript();
- void readVersionScript();
- void readDynamicList();
-
-private:
- void addFile(StringRef Path);
-
- void readAsNeeded();
- void readEntry();
- void readExtern();
- void readGroup();
- void readInclude();
- void readOutput();
- void readOutputArch();
- void readOutputFormat();
- void readPhdrs();
- void readSearchDir();
- void readSections();
- void readVersion();
- void readVersionScriptCommand();
-
- SymbolAssignment *readAssignment(StringRef Name);
- BytesDataCommand *readBytesDataCommand(StringRef Tok);
- uint32_t readFill();
- OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
- uint32_t readOutputSectionFiller(StringRef Tok);
- std::vector<StringRef> readOutputSectionPhdrs();
- InputSectionDescription *readInputSectionDescription(StringRef Tok);
- StringMatcher readFilePatterns();
- std::vector<SectionPattern> readInputSectionsList();
- InputSectionDescription *readInputSectionRules(StringRef FilePattern);
- unsigned readPhdrType();
- SortSectionPolicy readSortKind();
- SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
- SymbolAssignment *readProvideOrAssignment(StringRef Tok);
- void readSort();
- Expr readAssert();
-
- Expr readExpr();
- Expr readExpr1(Expr Lhs, int MinPrec);
- StringRef readParenLiteral();
- Expr readPrimary();
- Expr readTernary(Expr Cond);
- Expr readParenExpr();
-
- // For parsing version script.
- std::vector<SymbolVersion> readVersionExtern();
- void readAnonymousDeclaration();
- void readVersionDeclaration(StringRef VerStr);
- std::vector<SymbolVersion> readSymbols();
- void readLocals();
-
- ScriptConfiguration &Opt = *ScriptConfig;
- bool IsUnderSysroot;
-};
-
-void ScriptParser::readDynamicList() {
- expect("{");
- readAnonymousDeclaration();
- if (!atEOF())
- setError("EOF expected, but got " + next());
-}
-
-void ScriptParser::readVersionScript() {
- readVersionScriptCommand();
- if (!atEOF())
- setError("EOF expected, but got " + next());
-}
-
-void ScriptParser::readVersionScriptCommand() {
- if (consume("{")) {
- readAnonymousDeclaration();
- return;
- }
-
- while (!atEOF() && !Error && peek() != "}") {
- StringRef VerStr = next();
- if (VerStr == "{") {
- setError("anonymous version definition is used in "
- "combination with other version definitions");
- return;
- }
- expect("{");
- readVersionDeclaration(VerStr);
- }
-}
-
-void ScriptParser::readVersion() {
- expect("{");
- readVersionScriptCommand();
- expect("}");
-}
-
-void ScriptParser::readLinkerScript() {
- while (!atEOF()) {
- StringRef Tok = next();
- if (Tok == ";")
- continue;
-
- if (Tok == "ASSERT") {
- Opt.Commands.emplace_back(new AssertCommand(readAssert()));
- } else if (Tok == "ENTRY") {
- readEntry();
- } else if (Tok == "EXTERN") {
- readExtern();
- } else if (Tok == "GROUP" || Tok == "INPUT") {
- readGroup();
- } else if (Tok == "INCLUDE") {
- readInclude();
- } else if (Tok == "OUTPUT") {
- readOutput();
- } else if (Tok == "OUTPUT_ARCH") {
- readOutputArch();
- } else if (Tok == "OUTPUT_FORMAT") {
- readOutputFormat();
- } else if (Tok == "PHDRS") {
- readPhdrs();
- } else if (Tok == "SEARCH_DIR") {
- readSearchDir();
- } else if (Tok == "SECTIONS") {
- readSections();
- } else if (Tok == "VERSION") {
- readVersion();
- } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
- Opt.Commands.emplace_back(Cmd);
- } else {
- setError("unknown directive: " + Tok);
- }
- }
-}
-
-void ScriptParser::addFile(StringRef S) {
- if (IsUnderSysroot && S.startswith("/")) {
- SmallString<128> PathData;
- StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
- if (sys::fs::exists(Path)) {
- Driver->addFile(Saver.save(Path));
- return;
- }
- }
-
- if (sys::path::is_absolute(S)) {
- Driver->addFile(S);
- } else if (S.startswith("=")) {
- if (Config->Sysroot.empty())
- Driver->addFile(S.substr(1));
- else
- Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
- } else if (S.startswith("-l")) {
- Driver->addLibrary(S.substr(2));
- } else if (sys::fs::exists(S)) {
- Driver->addFile(S);
- } else {
- if (Optional<std::string> Path = findFromSearchPaths(S))
- Driver->addFile(Saver.save(*Path));
- else
- setError("unable to find " + S);
- }
-}
-
-void ScriptParser::readAsNeeded() {
- expect("(");
- bool Orig = Config->AsNeeded;
- Config->AsNeeded = true;
- while (!Error && !consume(")"))
- addFile(unquote(next()));
- Config->AsNeeded = Orig;
-}
-
-void ScriptParser::readEntry() {
- // -e <symbol> takes predecence over ENTRY(<symbol>).
- expect("(");
- StringRef Tok = next();
- if (Config->Entry.empty())
- Config->Entry = Tok;
- expect(")");
-}
-
-void ScriptParser::readExtern() {
- expect("(");
- while (!Error && !consume(")"))
- Config->Undefined.push_back(next());
-}
-
-void ScriptParser::readGroup() {
- expect("(");
- while (!Error && !consume(")")) {
- StringRef Tok = next();
- if (Tok == "AS_NEEDED")
- readAsNeeded();
- else
- addFile(unquote(Tok));
- }
-}
-
-void ScriptParser::readInclude() {
- StringRef Tok = unquote(next());
-
- // https://sourceware.org/binutils/docs/ld/File-Commands.html:
- // The file will be searched for in the current directory, and in any
- // directory specified with the -L option.
- if (sys::fs::exists(Tok)) {
- if (Optional<MemoryBufferRef> MB = readFile(Tok))
- tokenize(*MB);
- return;
- }
- if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
- if (Optional<MemoryBufferRef> MB = readFile(*Path))
- tokenize(*MB);
- return;
- }
- setError("cannot open " + Tok);
-}
-
-void ScriptParser::readOutput() {
- // -o <file> takes predecence over OUTPUT(<file>).
- expect("(");
- StringRef Tok = next();
- if (Config->OutputFile.empty())
- Config->OutputFile = unquote(Tok);
- expect(")");
-}
-
-void ScriptParser::readOutputArch() {
- // Error checking only for now.
- expect("(");
- skip();
- expect(")");
-}
-
-void ScriptParser::readOutputFormat() {
- // Error checking only for now.
- expect("(");
- skip();
- StringRef Tok = next();
- if (Tok == ")")
- return;
- if (Tok != ",") {
- setError("unexpected token: " + Tok);
- return;
- }
- skip();
- expect(",");
- skip();
- expect(")");
-}
-
-void ScriptParser::readPhdrs() {
- expect("{");
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- Opt.PhdrsCommands.push_back(
- {Tok, PT_NULL, false, false, UINT_MAX, nullptr});
- PhdrsCommand &PhdrCmd = Opt.PhdrsCommands.back();
-
- PhdrCmd.Type = readPhdrType();
- do {
- Tok = next();
- if (Tok == ";")
- break;
- if (Tok == "FILEHDR")
- PhdrCmd.HasFilehdr = true;
- else if (Tok == "PHDRS")
- PhdrCmd.HasPhdrs = true;
- else if (Tok == "AT")
- PhdrCmd.LMAExpr = readParenExpr();
- else if (Tok == "FLAGS") {
- expect("(");
- // Passing 0 for the value of dot is a bit of a hack. It means that
- // we accept expressions like ".|1".
- PhdrCmd.Flags = readExpr()(0);
- expect(")");
- } else
- setError("unexpected header attribute: " + Tok);
- } while (!Error);
- }
-}
-
-void ScriptParser::readSearchDir() {
- expect("(");
- StringRef Tok = next();
- if (!Config->Nostdlib)
- Config->SearchPaths.push_back(unquote(Tok));
- expect(")");
-}
-
-void ScriptParser::readSections() {
- Opt.HasSections = true;
- // -no-rosegment is used to avoid placing read only non-executable sections in
- // their own segment. We do the same if SECTIONS command is present in linker
- // script. See comment for computeFlags().
- Config->SingleRoRx = true;
-
- expect("{");
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- BaseCommand *Cmd = readProvideOrAssignment(Tok);
- if (!Cmd) {
- if (Tok == "ASSERT")
- Cmd = new AssertCommand(readAssert());
- else
- Cmd = readOutputSectionDescription(Tok);
- }
- Opt.Commands.emplace_back(Cmd);
- }
-}
-
-static int precedence(StringRef Op) {
- return StringSwitch<int>(Op)
- .Cases("*", "/", 5)
- .Cases("+", "-", 4)
- .Cases("<<", ">>", 3)
- .Cases("<", "<=", ">", ">=", "==", "!=", 2)
- .Cases("&", "|", 1)
- .Default(-1);
-}
-
-StringMatcher ScriptParser::readFilePatterns() {
- std::vector<StringRef> V;
- while (!Error && !consume(")"))
- V.push_back(next());
- return StringMatcher(V);
-}
-
-SortSectionPolicy ScriptParser::readSortKind() {
- if (consume("SORT") || consume("SORT_BY_NAME"))
- return SortSectionPolicy::Name;
- if (consume("SORT_BY_ALIGNMENT"))
- return SortSectionPolicy::Alignment;
- if (consume("SORT_BY_INIT_PRIORITY"))
- return SortSectionPolicy::Priority;
- if (consume("SORT_NONE"))
- return SortSectionPolicy::None;
- return SortSectionPolicy::Default;
-}
-
-// Method reads a list of sequence of excluded files and section globs given in
-// a following form: ((EXCLUDE_FILE(file_pattern+))? section_pattern+)+
-// Example: *(.foo.1 EXCLUDE_FILE (*a.o) .foo.2 EXCLUDE_FILE (*b.o) .foo.3)
-// The semantics of that is next:
-// * Include .foo.1 from every file.
-// * Include .foo.2 from every file but a.o
-// * Include .foo.3 from every file but b.o
-std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
- std::vector<SectionPattern> Ret;
- while (!Error && peek() != ")") {
- StringMatcher ExcludeFilePat;
- if (consume("EXCLUDE_FILE")) {
- expect("(");
- ExcludeFilePat = readFilePatterns();
- }
-
- std::vector<StringRef> V;
- while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
- V.push_back(next());
-
- if (!V.empty())
- Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
- else
- setError("section pattern is expected");
- }
- return Ret;
-}
-
-// Reads contents of "SECTIONS" directive. That directive contains a
-// list of glob patterns for input sections. The grammar is as follows.
-//
-// <patterns> ::= <section-list>
-// | <sort> "(" <section-list> ")"
-// | <sort> "(" <sort> "(" <section-list> ")" ")"
-//
-// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
-// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
-//
-// <section-list> is parsed by readInputSectionsList().
-InputSectionDescription *
-ScriptParser::readInputSectionRules(StringRef FilePattern) {
- auto *Cmd = new InputSectionDescription(FilePattern);
- expect("(");
- while (!Error && !consume(")")) {
- SortSectionPolicy Outer = readSortKind();
- SortSectionPolicy Inner = SortSectionPolicy::Default;
- std::vector<SectionPattern> V;
- if (Outer != SortSectionPolicy::Default) {
- expect("(");
- Inner = readSortKind();
- if (Inner != SortSectionPolicy::Default) {
- expect("(");
- V = readInputSectionsList();
- expect(")");
- } else {
- V = readInputSectionsList();
- }
- expect(")");
- } else {
- V = readInputSectionsList();
- }
-
- for (SectionPattern &Pat : V) {
- Pat.SortInner = Inner;
- Pat.SortOuter = Outer;
- }
-
- std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
- }
- return Cmd;
-}
-
-InputSectionDescription *
-ScriptParser::readInputSectionDescription(StringRef Tok) {
- // Input section wildcard can be surrounded by KEEP.
- // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
- if (Tok == "KEEP") {
- expect("(");
- StringRef FilePattern = next();
- InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
- expect(")");
- Opt.KeptSections.push_back(Cmd);
- return Cmd;
- }
- return readInputSectionRules(Tok);
-}
-
-void ScriptParser::readSort() {
- expect("(");
- expect("CONSTRUCTORS");
- expect(")");
-}
-
-Expr ScriptParser::readAssert() {
- expect("(");
- Expr E = readExpr();
- expect(",");
- StringRef Msg = unquote(next());
- expect(")");
- return [=](uint64_t Dot) {
- uint64_t V = E(Dot);
- if (!V)
- error(Msg);
- return V;
- };
-}
-
-// Reads a FILL(expr) command. We handle the FILL command as an
-// 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() {
- expect("(");
- uint32_t V = readOutputSectionFiller(next());
- expect(")");
- expect(";");
- return V;
-}
-
-OutputSectionCommand *
-ScriptParser::readOutputSectionDescription(StringRef OutSec) {
- OutputSectionCommand *Cmd = new OutputSectionCommand(OutSec);
- Cmd->Location = getCurrentLocation();
-
- // Read an address expression.
- // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html#Output-Section-Address
- if (peek() != ":")
- Cmd->AddrExpr = readExpr();
-
- expect(":");
-
- if (consume("AT"))
- Cmd->LMAExpr = readParenExpr();
- if (consume("ALIGN"))
- Cmd->AlignExpr = readParenExpr();
- if (consume("SUBALIGN"))
- Cmd->SubalignExpr = readParenExpr();
-
- // Parse constraints.
- if (consume("ONLY_IF_RO"))
- Cmd->Constraint = ConstraintKind::ReadOnly;
- if (consume("ONLY_IF_RW"))
- Cmd->Constraint = ConstraintKind::ReadWrite;
- expect("{");
-
- while (!Error && !consume("}")) {
- StringRef Tok = next();
- if (SymbolAssignment *Assignment = readProvideOrAssignment(Tok)) {
- Cmd->Commands.emplace_back(Assignment);
- } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
- Cmd->Commands.emplace_back(Data);
- } else if (Tok == "ASSERT") {
- Cmd->Commands.emplace_back(new AssertCommand(readAssert()));
- expect(";");
- } else if (Tok == "FILL") {
- Cmd->Filler = readFill();
- } else if (Tok == "SORT") {
- readSort();
- } else if (peek() == "(") {
- Cmd->Commands.emplace_back(readInputSectionDescription(Tok));
- } else {
- setError("unknown command " + Tok);
- }
- }
- Cmd->Phdrs = readOutputSectionPhdrs();
-
- if (consume("="))
- Cmd->Filler = readOutputSectionFiller(next());
- else if (peek().startswith("="))
- Cmd->Filler = readOutputSectionFiller(next().drop_front());
-
- return Cmd;
-}
-
-// Read "=<number>" where <number> is an octal/decimal/hexadecimal number.
-// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
-//
-// ld.gold is not fully compatible with ld.bfd. ld.bfd handles
-// hexstrings as blobs of arbitrary sizes, while ld.gold handles them
-// as 32-bit big-endian values. We will do the same as ld.gold does
-// because it's simpler than what ld.bfd does.
-uint32_t ScriptParser::readOutputSectionFiller(StringRef Tok) {
- uint32_t V;
- if (!Tok.getAsInteger(0, V))
- return V;
- setError("invalid filler expression: " + Tok);
- return 0;
-}
-
-SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
- expect("(");
- SymbolAssignment *Cmd = readAssignment(next());
- Cmd->Provide = Provide;
- Cmd->Hidden = Hidden;
- expect(")");
- expect(";");
- return Cmd;
-}
-
-SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
- SymbolAssignment *Cmd = nullptr;
- if (peek() == "=" || peek() == "+=") {
- Cmd = readAssignment(Tok);
- expect(";");
- } else if (Tok == "PROVIDE") {
- Cmd = readProvideHidden(true, false);
- } else if (Tok == "HIDDEN") {
- Cmd = readProvideHidden(false, true);
- } else if (Tok == "PROVIDE_HIDDEN") {
- Cmd = readProvideHidden(true, true);
- }
- return Cmd;
-}
-
-static uint64_t getSymbolValue(const Twine &Loc, StringRef S, uint64_t Dot) {
- if (S == ".")
- return Dot;
- return ScriptBase->getSymbolValue(Loc, S);
-}
-
-static bool isAbsolute(StringRef S) {
- if (S == ".")
- return false;
- return ScriptBase->isAbsolute(S);
-}
-
-SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
- StringRef Op = next();
- Expr E;
- assert(Op == "=" || Op == "+=");
- if (consume("ABSOLUTE")) {
- // The RHS may be something like "ABSOLUTE(.) & 0xff".
- // Call readExpr1 to read the whole expression.
- E = readExpr1(readParenExpr(), 0);
- E.IsAbsolute = [] { return true; };
- } else {
- E = readExpr();
- }
- if (Op == "+=") {
- std::string Loc = getCurrentLocation();
- E = [=](uint64_t Dot) {
- return getSymbolValue(Loc, Name, Dot) + E(Dot);
- };
- }
- return new SymbolAssignment(Name, E);
-}
-
-// This is an operator-precedence parser to parse a linker
-// script expression.
-Expr ScriptParser::readExpr() { return readExpr1(readPrimary(), 0); }
-
-static Expr combine(StringRef Op, Expr L, Expr R) {
- if (Op == "*")
- return [=](uint64_t Dot) { return L(Dot) * R(Dot); };
- if (Op == "/") {
- return [=](uint64_t Dot) -> uint64_t {
- uint64_t RHS = R(Dot);
- if (RHS == 0) {
- error("division by zero");
- return 0;
- }
- return L(Dot) / RHS;
- };
- }
- if (Op == "+")
- return {[=](uint64_t Dot) { return L(Dot) + R(Dot); },
- [=] { return L.IsAbsolute() && R.IsAbsolute(); },
- [=] {
- const OutputSectionBase *S = L.Section();
- return S ? S : R.Section();
- }};
- if (Op == "-")
- return [=](uint64_t Dot) { return L(Dot) - R(Dot); };
- if (Op == "<<")
- return [=](uint64_t Dot) { return L(Dot) << R(Dot); };
- if (Op == ">>")
- return [=](uint64_t Dot) { return L(Dot) >> R(Dot); };
- if (Op == "<")
- return [=](uint64_t Dot) { return L(Dot) < R(Dot); };
- if (Op == ">")
- return [=](uint64_t Dot) { return L(Dot) > R(Dot); };
- if (Op == ">=")
- return [=](uint64_t Dot) { return L(Dot) >= R(Dot); };
- if (Op == "<=")
- return [=](uint64_t Dot) { return L(Dot) <= R(Dot); };
- if (Op == "==")
- return [=](uint64_t Dot) { return L(Dot) == R(Dot); };
- if (Op == "!=")
- return [=](uint64_t Dot) { return L(Dot) != R(Dot); };
- if (Op == "&")
- return [=](uint64_t Dot) { return L(Dot) & R(Dot); };
- if (Op == "|")
- return [=](uint64_t Dot) { return L(Dot) | R(Dot); };
- llvm_unreachable("invalid operator");
-}
-
-// This is a part of the operator-precedence parser. This function
-// assumes that the remaining token stream starts with an operator.
-Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
- while (!atEOF() && !Error) {
- // Read an operator and an expression.
- if (consume("?"))
- return readTernary(Lhs);
- StringRef Op1 = peek();
- if (precedence(Op1) < MinPrec)
- break;
- skip();
- Expr Rhs = readPrimary();
-
- // Evaluate the remaining part of the expression first if the
- // next operator has greater precedence than the previous one.
- // For example, if we have read "+" and "3", and if the next
- // operator is "*", then we'll evaluate 3 * ... part first.
- while (!atEOF()) {
- StringRef Op2 = peek();
- if (precedence(Op2) <= precedence(Op1))
- break;
- Rhs = readExpr1(Rhs, precedence(Op2));
- }
-
- Lhs = combine(Op1, Lhs, Rhs);
- }
- return Lhs;
-}
-
-uint64_t static getConstant(StringRef S) {
- if (S == "COMMONPAGESIZE")
- return Target->PageSize;
- if (S == "MAXPAGESIZE")
- return Config->MaxPageSize;
- error("unknown constant: " + S);
- return 0;
-}
-
-// Parses Tok as an integer. Returns true if successful.
-// It recognizes hexadecimal (prefixed with "0x" or suffixed with "H")
-// and decimal numbers. Decimal numbers may have "K" (kilo) or
-// "M" (mega) prefixes.
-static bool readInteger(StringRef Tok, uint64_t &Result) {
- // Negative number
- if (Tok.startswith("-")) {
- if (!readInteger(Tok.substr(1), Result))
- return false;
- Result = -Result;
- return true;
- }
-
- // Hexadecimal
- if (Tok.startswith_lower("0x"))
- return !Tok.substr(2).getAsInteger(16, Result);
- if (Tok.endswith_lower("H"))
- return !Tok.drop_back().getAsInteger(16, Result);
-
- // Decimal
- int Suffix = 1;
- if (Tok.endswith_lower("K")) {
- Suffix = 1024;
- Tok = Tok.drop_back();
- } else if (Tok.endswith_lower("M")) {
- Suffix = 1024 * 1024;
- Tok = Tok.drop_back();
- }
- if (Tok.getAsInteger(10, Result))
- return false;
- Result *= Suffix;
- return true;
-}
-
-BytesDataCommand *ScriptParser::readBytesDataCommand(StringRef Tok) {
- int Size = StringSwitch<unsigned>(Tok)
- .Case("BYTE", 1)
- .Case("SHORT", 2)
- .Case("LONG", 4)
- .Case("QUAD", 8)
- .Default(-1);
- if (Size == -1)
- return nullptr;
-
- return new BytesDataCommand(readParenExpr(), Size);
-}
-
-StringRef ScriptParser::readParenLiteral() {
- expect("(");
- StringRef Tok = next();
- expect(")");
- return Tok;
-}
-
-Expr ScriptParser::readPrimary() {
- if (peek() == "(")
- return readParenExpr();
-
- StringRef Tok = next();
- std::string Location = getCurrentLocation();
-
- if (Tok == "~") {
- Expr E = readPrimary();
- return [=](uint64_t Dot) { return ~E(Dot); };
- }
- if (Tok == "-") {
- Expr E = readPrimary();
- return [=](uint64_t Dot) { return -E(Dot); };
- }
-
- // Built-in functions are parsed here.
- // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
- if (Tok == "ADDR") {
- StringRef Name = readParenLiteral();
- return {[=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->Addr;
- },
- [=] { return false; },
- [=] { return ScriptBase->getOutputSection(Location, Name); }};
- }
- if (Tok == "LOADADDR") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->getLMA();
- };
- }
- if (Tok == "ASSERT")
- return readAssert();
- if (Tok == "ALIGN") {
- expect("(");
- Expr E = readExpr();
- if (consume(",")) {
- Expr E2 = readExpr();
- expect(")");
- return [=](uint64_t Dot) { return alignTo(E(Dot), E2(Dot)); };
- }
- expect(")");
- return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
- }
- if (Tok == "CONSTANT") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return getConstant(Name); };
- }
- if (Tok == "DEFINED") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->isDefined(Name) ? 1 : 0; };
- }
- if (Tok == "SEGMENT_START") {
- expect("(");
- skip();
- expect(",");
- Expr E = readExpr();
- expect(")");
- return [=](uint64_t Dot) { return E(Dot); };
- }
- if (Tok == "DATA_SEGMENT_ALIGN") {
- expect("(");
- Expr E = readExpr();
- expect(",");
- readExpr();
- expect(")");
- return [=](uint64_t Dot) { return alignTo(Dot, E(Dot)); };
- }
- if (Tok == "DATA_SEGMENT_END") {
- expect("(");
- expect(".");
- expect(")");
- return [](uint64_t Dot) { return Dot; };
- }
- // GNU linkers implements more complicated logic to handle
- // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and just align to
- // the next page boundary for simplicity.
- if (Tok == "DATA_SEGMENT_RELRO_END") {
- expect("(");
- readExpr();
- expect(",");
- readExpr();
- expect(")");
- return [](uint64_t Dot) { return alignTo(Dot, Target->PageSize); };
- }
- if (Tok == "SIZEOF") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) { return ScriptBase->getOutputSectionSize(Name); };
- }
- if (Tok == "ALIGNOF") {
- StringRef Name = readParenLiteral();
- return [=](uint64_t Dot) {
- return ScriptBase->getOutputSection(Location, Name)->Addralign;
- };
- }
- if (Tok == "SIZEOF_HEADERS")
- return [=](uint64_t Dot) { return ScriptBase->getHeaderSize(); };
-
- // Tok is a literal number.
- uint64_t V;
- if (readInteger(Tok, V))
- return [=](uint64_t Dot) { return V; };
-
- // Tok is a symbol name.
- if (Tok != "." && !isValidCIdentifier(Tok))
- setError("malformed number: " + Tok);
- return {[=](uint64_t Dot) { return getSymbolValue(Location, Tok, Dot); },
- [=] { return isAbsolute(Tok); },
- [=] { return ScriptBase->getSymbolSection(Tok); }};
-}
-
-Expr ScriptParser::readTernary(Expr Cond) {
- Expr L = readExpr();
- expect(":");
- Expr R = readExpr();
- return [=](uint64_t Dot) { return Cond(Dot) ? L(Dot) : R(Dot); };
-}
-
-Expr ScriptParser::readParenExpr() {
- expect("(");
- Expr E = readExpr();
- expect(")");
- return E;
-}
-
-std::vector<StringRef> ScriptParser::readOutputSectionPhdrs() {
- std::vector<StringRef> Phdrs;
- while (!Error && peek().startswith(":")) {
- StringRef Tok = next();
- Phdrs.push_back((Tok.size() == 1) ? next() : Tok.substr(1));
- }
- return Phdrs;
-}
-
-// Read a program header type name. The next token must be a
-// name of a program header type or a constant (e.g. "0x3").
-unsigned ScriptParser::readPhdrType() {
- StringRef Tok = next();
- uint64_t Val;
- if (readInteger(Tok, Val))
- return Val;
-
- unsigned Ret = StringSwitch<unsigned>(Tok)
- .Case("PT_NULL", PT_NULL)
- .Case("PT_LOAD", PT_LOAD)
- .Case("PT_DYNAMIC", PT_DYNAMIC)
- .Case("PT_INTERP", PT_INTERP)
- .Case("PT_NOTE", PT_NOTE)
- .Case("PT_SHLIB", PT_SHLIB)
- .Case("PT_PHDR", PT_PHDR)
- .Case("PT_TLS", PT_TLS)
- .Case("PT_GNU_EH_FRAME", PT_GNU_EH_FRAME)
- .Case("PT_GNU_STACK", PT_GNU_STACK)
- .Case("PT_GNU_RELRO", PT_GNU_RELRO)
- .Case("PT_OPENBSD_RANDOMIZE", PT_OPENBSD_RANDOMIZE)
- .Case("PT_OPENBSD_WXNEEDED", PT_OPENBSD_WXNEEDED)
- .Case("PT_OPENBSD_BOOTDATA", PT_OPENBSD_BOOTDATA)
- .Default(-1);
-
- if (Ret == (unsigned)-1) {
- setError("invalid program header type: " + Tok);
- return PT_NULL;
- }
- return Ret;
-}
-
-// Reads a list of symbols, e.g. "{ global: foo; bar; local: *; };".
-void ScriptParser::readAnonymousDeclaration() {
- // Read global symbols first. "global:" is default, so if there's
- // no label, we assume global symbols.
- if (consume("global:") || peek() != "local:")
- Config->VersionScriptGlobals = readSymbols();
-
- readLocals();
- expect("}");
- expect(";");
-}
-
-void ScriptParser::readLocals() {
- if (!consume("local:"))
- return;
- std::vector<SymbolVersion> Locals = readSymbols();
- for (SymbolVersion V : Locals) {
- if (V.Name == "*") {
- Config->DefaultSymbolVersion = VER_NDX_LOCAL;
- continue;
- }
- Config->VersionScriptLocals.push_back(V);
- }
-}
-
-// Reads a list of symbols, e.g. "VerStr { global: foo; bar; local: *; };".
-void ScriptParser::readVersionDeclaration(StringRef VerStr) {
- // Identifiers start at 2 because 0 and 1 are reserved
- // for VER_NDX_LOCAL and VER_NDX_GLOBAL constants.
- uint16_t VersionId = Config->VersionDefinitions.size() + 2;
- Config->VersionDefinitions.push_back({VerStr, VersionId});
-
- // Read global symbols.
- if (consume("global:") || peek() != "local:")
- Config->VersionDefinitions.back().Globals = readSymbols();
-
- readLocals();
- expect("}");
-
- // Each version may have a parent version. For example, "Ver2"
- // defined as "Ver2 { global: foo; local: *; } Ver1;" has "Ver1"
- // as a parent. This version hierarchy is, probably against your
- // instinct, purely for hint; the runtime doesn't care about it
- // at all. In LLD, we simply ignore it.
- if (peek() != ";")
- skip();
- expect(";");
-}
-
-// Reads a list of symbols for a versions cript.
-std::vector<SymbolVersion> ScriptParser::readSymbols() {
- std::vector<SymbolVersion> Ret;
- for (;;) {
- if (consume("extern")) {
- for (SymbolVersion V : readVersionExtern())
- Ret.push_back(V);
- continue;
- }
-
- if (peek() == "}" || peek() == "local:" || Error)
- break;
- StringRef Tok = next();
- Ret.push_back({unquote(Tok), false, hasWildcard(Tok)});
- expect(";");
- }
- return Ret;
-}
-
-// Reads an "extern C++" directive, e.g.,
-// "extern "C++" { ns::*; "f(int, double)"; };"
-std::vector<SymbolVersion> ScriptParser::readVersionExtern() {
- StringRef Tok = next();
- bool IsCXX = Tok == "\"C++\"";
- if (!IsCXX && Tok != "\"C\"")
- setError("Unknown language");
- expect("{");
-
- std::vector<SymbolVersion> Ret;
- while (!Error && peek() != "}") {
- StringRef Tok = next();
- bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok);
- Ret.push_back({unquote(Tok), IsCXX, HasWildcard});
- expect(";");
- }
-
- expect("}");
- expect(";");
- return Ret;
-}
-
-void elf::readLinkerScript(MemoryBufferRef MB) {
- ScriptParser(MB).readLinkerScript();
-}
-
-void elf::readVersionScript(MemoryBufferRef MB) {
- ScriptParser(MB).readVersionScript();
-}
-
-void elf::readDynamicList(MemoryBufferRef MB) {
- ScriptParser(MB).readDynamicList();
-}
-
-template class elf::LinkerScript<ELF32LE>;
-template class elf::LinkerScript<ELF32BE>;
-template class elf::LinkerScript<ELF64LE>;
-template class elf::LinkerScript<ELF64BE>;
diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h
index 505162f0ab43..04a388efb4e9 100644
--- a/ELF/LinkerScript.h
+++ b/ELF/LinkerScript.h
@@ -15,6 +15,7 @@
#include "Writer.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -28,45 +29,32 @@ namespace lld {
namespace elf {
class DefinedCommon;
-class ScriptParser;
class SymbolBody;
-template <class ELFT> class InputSectionBase;
-template <class ELFT> class InputSection;
-class OutputSectionBase;
-template <class ELFT> class OutputSectionFactory;
-class InputSectionData;
+class InputSectionBase;
+class InputSection;
+class OutputSection;
+class OutputSectionFactory;
+class InputSectionBase;
+class SectionBase;
+
+struct ExprValue {
+ SectionBase *Sec;
+ uint64_t Val;
+ bool ForceAbsolute;
+
+ ExprValue(SectionBase *Sec, bool ForceAbsolute, uint64_t Val)
+ : Sec(Sec), Val(Val), ForceAbsolute(ForceAbsolute) {}
+ ExprValue(SectionBase *Sec, uint64_t Val) : ExprValue(Sec, false, Val) {}
+ ExprValue(uint64_t Val) : ExprValue(nullptr, Val) {}
+ bool isAbsolute() const { return ForceAbsolute || Sec == nullptr; }
+ uint64_t getValue() const;
+ uint64_t getSecAddr() const;
+};
// This represents an expression in the linker script.
// ScriptParser::readExpr reads an expression and returns an Expr.
-// Later, we evaluate the expression by calling the function
-// with the value of special context variable ".".
-struct Expr {
- std::function<uint64_t(uint64_t)> Val;
- std::function<bool()> IsAbsolute;
-
- // If expression is section-relative the function below is used
- // to get the output section pointer.
- std::function<const OutputSectionBase *()> Section;
-
- uint64_t operator()(uint64_t Dot) const { return Val(Dot); }
- operator bool() const { return (bool)Val; }
-
- Expr(std::function<uint64_t(uint64_t)> Val, std::function<bool()> IsAbsolute,
- std::function<const OutputSectionBase *()> Section)
- : Val(Val), IsAbsolute(IsAbsolute), Section(Section) {}
- template <typename T>
- Expr(T V) : Expr(V, [] { return true; }, [] { return nullptr; }) {}
- Expr() : Expr(nullptr) {}
-};
-
-// Parses a linker script. Calling this function updates
-// Config and ScriptConfig.
-void readLinkerScript(MemoryBufferRef MB);
-
-// Parses a version script.
-void readVersionScript(MemoryBufferRef MB);
-
-void readDynamicList(MemoryBufferRef MB);
+// Later, we evaluate the expression by calling the function.
+typedef std::function<ExprValue()> Expr;
// This enum is used to implement linker script SECTIONS command.
// https://sourceware.org/binutils/docs/ld/SECTIONS.html#SECTIONS
@@ -80,16 +68,13 @@ enum SectionsCommandKind {
struct BaseCommand {
BaseCommand(int K) : Kind(K) {}
-
- virtual ~BaseCommand() = default;
-
int Kind;
};
// This represents ". = <expr>" or "<symbol> = <expr>".
struct SymbolAssignment : BaseCommand {
- SymbolAssignment(StringRef Name, Expr E)
- : BaseCommand(AssignmentKind), Name(Name), Expression(E) {}
+ SymbolAssignment(StringRef Name, Expr E, std::string Loc)
+ : BaseCommand(AssignmentKind), Name(Name), Expression(E), Location(Loc) {}
static bool classof(const BaseCommand *C);
@@ -103,6 +88,9 @@ struct SymbolAssignment : BaseCommand {
// Command attributes for PROVIDE, HIDDEN and PROVIDE_HIDDEN.
bool Provide = false;
bool Hidden = false;
+
+ // Holds file name and line number for error reporting.
+ std::string Location;
};
// Linker scripts allow additional constraints to be put on ouput sections.
@@ -111,22 +99,37 @@ struct SymbolAssignment : BaseCommand {
// with ONLY_IF_RW is created if all input sections are RW.
enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
+// This struct is used to represent the location and size of regions of
+// target memory. Instances of the struct are created by parsing the
+// MEMORY command.
+struct MemoryRegion {
+ std::string Name;
+ uint64_t Origin;
+ uint64_t Length;
+ uint64_t Offset;
+ uint32_t Flags;
+ uint32_t NegFlags;
+};
+
struct OutputSectionCommand : BaseCommand {
OutputSectionCommand(StringRef Name)
: BaseCommand(OutputSectionKind), Name(Name) {}
static bool classof(const BaseCommand *C);
+ OutputSection *Sec = nullptr;
+ MemoryRegion *MemRegion = nullptr;
StringRef Name;
Expr AddrExpr;
Expr AlignExpr;
Expr LMAExpr;
Expr SubalignExpr;
- std::vector<std::unique_ptr<BaseCommand>> Commands;
+ std::vector<BaseCommand *> Commands;
std::vector<StringRef> Phdrs;
- uint32_t Filler = 0;
+ llvm::Optional<uint32_t> Filler;
ConstraintKind Constraint = ConstraintKind::NoConstraint;
std::string Location;
+ std::string MemoryRegionName;
};
// This struct represents one section match pattern in SECTIONS() command.
@@ -154,7 +157,7 @@ struct InputSectionDescription : BaseCommand {
// will be associated with this InputSectionDescription.
std::vector<SectionPattern> SectionPatterns;
- std::vector<InputSectionData *> Sections;
+ std::vector<InputSectionBase *> Sections;
};
// Represents an ASSERT().
@@ -187,25 +190,10 @@ struct PhdrsCommand {
Expr LMAExpr;
};
-class LinkerScriptBase {
-protected:
- ~LinkerScriptBase() = default;
-
-public:
- virtual uint64_t getHeaderSize() = 0;
- virtual uint64_t getSymbolValue(const Twine &Loc, StringRef S) = 0;
- virtual bool isDefined(StringRef S) = 0;
- virtual bool isAbsolute(StringRef S) = 0;
- virtual const OutputSectionBase *getSymbolSection(StringRef S) = 0;
- virtual const OutputSectionBase *getOutputSection(const Twine &Loc,
- StringRef S) = 0;
- virtual uint64_t getOutputSectionSize(StringRef S) = 0;
-};
-
// ScriptConfiguration holds linker script parse results.
struct ScriptConfiguration {
// Used to assign addresses to sections.
- std::vector<std::unique_ptr<BaseCommand>> Commands;
+ std::vector<BaseCommand *> Commands;
// Used to assign sections to headers.
std::vector<PhdrsCommand> PhdrsCommands;
@@ -215,20 +203,60 @@ struct ScriptConfiguration {
// List of section patterns specified with KEEP commands. They will
// be kept even if they are unused and --gc-sections is specified.
std::vector<InputSectionDescription *> KeptSections;
+
+ // A map from memory region name to a memory region descriptor.
+ llvm::DenseMap<llvm::StringRef, MemoryRegion> MemoryRegions;
+
+ // A list of symbols referenced by the script.
+ std::vector<llvm::StringRef> ReferencedSymbols;
};
-extern ScriptConfiguration *ScriptConfig;
+class LinkerScript {
+protected:
+ void assignSymbol(SymbolAssignment *Cmd, bool InSec);
+ void setDot(Expr E, const Twine &Loc, bool InSec);
+
+ std::vector<InputSectionBase *>
+ computeInputSections(const InputSectionDescription *);
+
+ std::vector<InputSectionBase *>
+ createInputSectionList(OutputSectionCommand &Cmd);
+
+ std::vector<size_t> getPhdrIndices(StringRef SectionName);
+ size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
+
+ MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd);
+
+ void switchTo(OutputSection *Sec);
+ void flush();
+ void output(InputSection *Sec);
+ void process(BaseCommand &Base);
-// This is a runner of the linker script.
-template <class ELFT> class LinkerScript final : public LinkerScriptBase {
- typedef typename ELFT::uint uintX_t;
+ OutputSection *Aether;
+ bool ErrorOnMissingSection = false;
+
+ uint64_t Dot;
+ uint64_t ThreadBssOffset = 0;
+
+ std::function<uint64_t()> LMAOffset;
+ OutputSection *CurOutSec = nullptr;
+ MemoryRegion *CurMemRegion = nullptr;
+
+ llvm::DenseSet<OutputSection *> AlreadyOutputOS;
+ llvm::DenseSet<InputSectionBase *> AlreadyOutputIS;
public:
- LinkerScript();
- ~LinkerScript();
+ bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }
+ uint64_t getDot() { return Dot; }
+ OutputSection *getOutputSection(const Twine &Loc, StringRef S);
+ uint64_t getOutputSectionSize(StringRef S);
+ void discard(ArrayRef<InputSectionBase *> V);
- void processCommands(OutputSectionFactory<ELFT> &Factory);
- void addOrphanSections(OutputSectionFactory<ELFT> &Factory);
+ ExprValue getSymbolValue(const Twine &Loc, StringRef S);
+ bool isDefined(StringRef S);
+
+ std::vector<OutputSection *> *OutputSections;
+ void addOrphanSections(OutputSectionFactory &Factory);
void removeEmptyCommands();
void adjustSectionsBeforeSorting();
void adjustSectionsAfterSorting();
@@ -236,61 +264,24 @@ public:
std::vector<PhdrEntry> createPhdrs();
bool ignoreInterpSection();
- uint32_t getFiller(StringRef Name);
- void writeDataBytes(StringRef Name, uint8_t *Buf);
+ llvm::Optional<uint32_t> getFiller(StringRef Name);
bool hasLMA(StringRef Name);
- bool shouldKeep(InputSectionBase<ELFT> *S);
+ bool shouldKeep(InputSectionBase *S);
void assignOffsets(OutputSectionCommand *Cmd);
void placeOrphanSections();
+ void processNonSectionCommands();
void assignAddresses(std::vector<PhdrEntry> &Phdrs);
- bool hasPhdrsCommands();
- uint64_t getHeaderSize() override;
- uint64_t getSymbolValue(const Twine &Loc, StringRef S) override;
- bool isDefined(StringRef S) override;
- bool isAbsolute(StringRef S) override;
- const OutputSectionBase *getSymbolSection(StringRef S) override;
- const OutputSectionBase *getOutputSection(const Twine &Loc,
- StringRef S) override;
- uint64_t getOutputSectionSize(StringRef S) override;
-
- std::vector<OutputSectionBase *> *OutputSections;
-
int getSectionIndex(StringRef Name);
-private:
- void computeInputSections(InputSectionDescription *);
-
- void addSection(OutputSectionFactory<ELFT> &Factory,
- InputSectionBase<ELFT> *Sec, StringRef Name);
- void discard(ArrayRef<InputSectionBase<ELFT> *> V);
-
- std::vector<InputSectionBase<ELFT> *>
- createInputSectionList(OutputSectionCommand &Cmd);
-
- // "ScriptConfig" is a bit too long, so define a short name for it.
- ScriptConfiguration &Opt = *ScriptConfig;
-
- std::vector<size_t> getPhdrIndices(StringRef SectionName);
- size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName);
+ void writeDataBytes(StringRef Name, uint8_t *Buf);
+ void addSymbol(SymbolAssignment *Cmd);
+ void processCommands(OutputSectionFactory &Factory);
- uintX_t Dot;
- uintX_t LMAOffset = 0;
- OutputSectionBase *CurOutSec = nullptr;
- uintX_t ThreadBssOffset = 0;
- void switchTo(OutputSectionBase *Sec);
- void flush();
- void output(InputSection<ELFT> *Sec);
- void process(BaseCommand &Base);
- llvm::DenseSet<OutputSectionBase *> AlreadyOutputOS;
- llvm::DenseSet<InputSectionData *> AlreadyOutputIS;
+ // Parsed linker script configurations are set to this struct.
+ ScriptConfiguration Opt;
};
-// Variable template is a C++14 feature, so we can't template
-// a global variable. Use a struct to workaround.
-template <class ELFT> struct Script { static LinkerScript<ELFT> *X; };
-template <class ELFT> LinkerScript<ELFT> *Script<ELFT>::X;
-
-extern LinkerScriptBase *ScriptBase;
+extern LinkerScript *Script;
} // end namespace elf
} // end namespace lld
diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp
new file mode 100644
index 000000000000..31c8091bb6a1
--- /dev/null
+++ b/ELF/MapFile.cpp
@@ -0,0 +1,131 @@
+//===- MapFile.cpp --------------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the -Map option. It shows lists in order and
+// hierarchically the output sections, input sections, input files and
+// symbol:
+//
+// Address Size Align Out In File Symbol
+// =================================================================
+// 00201000 00000015 4 .text
+// 00201000 0000000e 4 .text
+// 00201000 0000000e 4 test.o
+// 0020100e 00000000 0 local
+// 00201005 00000000 0 f(int)
+//
+//===----------------------------------------------------------------------===//
+
+#include "MapFile.h"
+#include "InputFiles.h"
+#include "Strings.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+
+using namespace lld;
+using namespace lld::elf;
+
+static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
+ uint64_t Size, uint64_t Align, StringRef Name) {
+ OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align)
+ << left_justify(Name, 7);
+}
+
+static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
+ uint64_t Size, uint64_t Align, StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeOutSecLine(OS, Width, Address, Size, Align, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address,
+ uint64_t Size, uint64_t Align, StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeInSecLine(OS, Width, Address, Size, Align, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address,
+ uint64_t Size, StringRef Name) {
+ // Pass an empty name to align the text to the correct column.
+ writeFileLine(OS, Width, Address, Size, 0, "");
+ OS << ' ' << left_justify(Name, 7);
+}
+
+template <class ELFT>
+static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS,
+ StringRef &PrevName) {
+ int Width = ELFT::Is64Bits ? 16 : 8;
+ StringRef Name = IS->Name;
+ if (Name != PrevName) {
+ writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
+ IS->Alignment, Name);
+ OS << '\n';
+ PrevName = Name;
+ }
+
+ elf::ObjectFile<ELFT> *File = IS->template getFile<ELFT>();
+ if (!File)
+ return;
+ writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
+ IS->Alignment, toString(File));
+ OS << '\n';
+
+ for (SymbolBody *Sym : File->getSymbols()) {
+ auto *DR = dyn_cast<DefinedRegular>(Sym);
+ if (!DR)
+ continue;
+ if (DR->Section != IS)
+ continue;
+ if (DR->isSection())
+ continue;
+ writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize<ELFT>(),
+ toString(*Sym));
+ OS << '\n';
+ }
+}
+
+template <class ELFT>
+static void writeMapFile2(raw_fd_ostream &OS,
+ ArrayRef<OutputSection *> OutputSections) {
+ int Width = ELFT::Is64Bits ? 16 : 8;
+
+ OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
+ << " Align Out In File Symbol\n";
+
+ for (OutputSection *Sec : OutputSections) {
+ writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name);
+ OS << '\n';
+
+ StringRef PrevName = "";
+ for (InputSection *IS : Sec->Sections) {
+ writeInputSection<ELFT>(OS, IS, PrevName);
+ }
+ }
+}
+
+template <class ELFT>
+void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
+ if (Config->MapFile.empty())
+ return;
+
+ std::error_code EC;
+ raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
+ if (EC)
+ error("cannot open " + Config->MapFile + ": " + EC.message());
+ else
+ writeMapFile2<ELFT>(OS, OutputSections);
+}
+
+template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>);
+template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>);
+template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>);
+template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>);
diff --git a/ELF/MapFile.h b/ELF/MapFile.h
new file mode 100644
index 000000000000..24d636890e53
--- /dev/null
+++ b/ELF/MapFile.h
@@ -0,0 +1,22 @@
+//===- MapFile.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_MAPFILE_H
+#define LLD_ELF_MAPFILE_H
+
+#include "OutputSections.h"
+
+namespace lld {
+namespace elf {
+template <class ELFT>
+void writeMapFile(llvm::ArrayRef<OutputSection *> OutputSections);
+}
+}
+
+#endif
diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp
index 8d129fc3ff13..ee499265886e 100644
--- a/ELF/MarkLive.cpp
+++ b/ELF/MarkLive.cpp
@@ -22,6 +22,7 @@
#include "InputSection.h"
#include "LinkerScript.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@@ -44,51 +45,59 @@ using namespace lld::elf;
namespace {
// A resolved relocation. The Sec and Offset fields are set if the relocation
// was resolved to an offset within a section.
-template <class ELFT> struct ResolvedReloc {
- InputSectionBase<ELFT> *Sec;
- typename ELFT::uint Offset;
+struct ResolvedReloc {
+ InputSectionBase *Sec;
+ uint64_t Offset;
};
} // end anonymous namespace
template <class ELFT>
-static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rel &Rel) {
return Target->getImplicitAddend(Sec.Data.begin() + Rel.r_offset,
- Rel.getType(Config->Mips64EL));
+ Rel.getType(Config->IsMips64EL));
}
template <class ELFT>
-static typename ELFT::uint getAddend(InputSectionBase<ELFT> &Sec,
+static typename ELFT::uint getAddend(InputSectionBase &Sec,
const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
+// There are normally few input sections whose names are valid C
+// identifiers, so we just store a std::vector instead of a multimap.
+static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections;
+
template <class ELFT, class RelT>
-static ResolvedReloc<ELFT> resolveReloc(InputSectionBase<ELFT> &Sec,
- RelT &Rel) {
- SymbolBody &B = Sec.getFile()->getRelocTargetSym(Rel);
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
- if (!D || !D->Section)
- return {nullptr, 0};
- typename ELFT::uint Offset = D->Value;
- if (D->isSection())
- Offset += getAddend(Sec, Rel);
- return {D->Section->Repl, Offset};
+static void resolveReloc(InputSectionBase &Sec, RelT &Rel,
+ std::function<void(ResolvedReloc)> Fn) {
+ SymbolBody &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ if (auto *D = dyn_cast<DefinedRegular>(&B)) {
+ if (!D->Section)
+ return;
+ typename ELFT::uint Offset = D->Value;
+ if (D->isSection())
+ Offset += getAddend<ELFT>(Sec, Rel);
+ Fn({cast<InputSectionBase>(D->Section)->Repl, Offset});
+ } else if (auto *U = dyn_cast<Undefined>(&B)) {
+ for (InputSectionBase *Sec : CNamedSections.lookup(U->getName()))
+ Fn({Sec, 0});
+ }
}
// Calls Fn for each section that Sec refers to via relocations.
template <class ELFT>
-static void forEachSuccessor(InputSection<ELFT> &Sec,
- std::function<void(ResolvedReloc<ELFT>)> Fn) {
+static void forEachSuccessor(InputSection &Sec,
+ std::function<void(ResolvedReloc)> Fn) {
if (Sec.AreRelocsRela) {
- for (const typename ELFT::Rela &Rel : Sec.relas())
- Fn(resolveReloc(Sec, Rel));
+ for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
} else {
- for (const typename ELFT::Rel &Rel : Sec.rels())
- Fn(resolveReloc(Sec, Rel));
+ for (const typename ELFT::Rel &Rel : Sec.template rels<ELFT>())
+ resolveReloc<ELFT>(Sec, Rel, Fn);
}
- if (Sec.DependentSection)
- Fn({Sec.DependentSection, 0});
+ for (InputSectionBase *IS : Sec.DependentSections)
+ Fn({IS, 0});
}
// The .eh_frame section is an unfortunate special case.
@@ -106,9 +115,8 @@ static void forEachSuccessor(InputSection<ELFT> &Sec,
// the gc pass. With that we would be able to also gc some sections holding
// LSDAs and personality functions if we found that they were unused.
template <class ELFT, class RelTy>
-static void
-scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
- std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels,
+ std::function<void(ResolvedReloc)> Enqueue) {
const endianness E = ELFT::TargetEndianness;
for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
EhSectionPiece &Piece = EH.Pieces[I];
@@ -118,7 +126,7 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
if (read32<E>(Piece.data().data() + 4) == 0) {
// This is a CIE, we only need to worry about the first relocation. It is
// known to point to the personality function.
- Enqueue(resolveReloc(EH, Rels[FirstRelI]));
+ resolveReloc<ELFT>(EH, Rels[FirstRelI], Enqueue);
continue;
}
// This is a FDE. The relocations point to the described function or to
@@ -129,37 +137,37 @@ scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
const RelTy &Rel = Rels[I2];
if (Rel.r_offset >= PieceEnd)
break;
- ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
- if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
- continue;
- if (R.Sec->Flags & SHF_EXECINSTR)
- continue;
- Enqueue({R.Sec, 0});
+ resolveReloc<ELFT>(EH, Rels[I2], [&](ResolvedReloc R) {
+ if (!R.Sec || R.Sec == &InputSection::Discarded)
+ return;
+ if (R.Sec->Flags & SHF_EXECINSTR)
+ return;
+ Enqueue({R.Sec, 0});
+ });
}
}
}
template <class ELFT>
-static void
-scanEhFrameSection(EhInputSection<ELFT> &EH,
- std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+static void scanEhFrameSection(EhInputSection &EH,
+ std::function<void(ResolvedReloc)> Enqueue) {
if (!EH.NumRelocations)
return;
// Unfortunately we need to split .eh_frame early since some relocations in
// .eh_frame keep other section alive and some don't.
- EH.split();
+ EH.split<ELFT>();
if (EH.AreRelocsRela)
- scanEhFrameSection(EH, EH.relas(), Enqueue);
+ scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Enqueue);
else
- scanEhFrameSection(EH, EH.rels(), Enqueue);
+ scanEhFrameSection<ELFT>(EH, EH.template rels<ELFT>(), Enqueue);
}
// We do not garbage-collect two types of sections:
// 1) Sections used by the loader (.init, .fini, .ctors, .dtors or .jcr)
// 2) Non-allocatable sections which typically contain debugging information
-template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
+template <class ELFT> static bool isReserved(InputSectionBase *Sec) {
switch (Sec->Type) {
case SHT_FINI_ARRAY:
case SHT_INIT_ARRAY:
@@ -170,12 +178,7 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
if (!(Sec->Flags & SHF_ALLOC))
return true;
- // We do not want to reclaim sections if they can be referred
- // by __start_* and __stop_* symbols.
StringRef S = Sec->Name;
- if (isValidCIdentifier(S))
- return true;
-
return S.startswith(".ctors") || S.startswith(".dtors") ||
S.startswith(".init") || S.startswith(".fini") ||
S.startswith(".jcr");
@@ -186,14 +189,15 @@ template <class ELFT> static bool isReserved(InputSectionBase<ELFT> *Sec) {
// Starting from GC-root sections, this function visits all reachable
// sections to set their "Live" bits.
template <class ELFT> void elf::markLive() {
- SmallVector<InputSection<ELFT> *, 256> Q;
+ SmallVector<InputSection *, 256> Q;
+ CNamedSections.clear();
- auto Enqueue = [&](ResolvedReloc<ELFT> R) {
+ auto Enqueue = [&](ResolvedReloc R) {
// Skip over discarded sections. This in theory shouldn't happen, because
// the ELF spec doesn't allow a relocation to point to a deduplicated
// COMDAT section directly. Unfortunately this happens in practice (e.g.
// .eh_frame) so we need to add a check.
- if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ if (R.Sec == &InputSection::Discarded)
return;
// We don't gc non alloc sections.
@@ -203,20 +207,20 @@ template <class ELFT> void elf::markLive() {
// Usually, a whole section is marked as live or dead, but in mergeable
// (splittable) sections, each piece of data has independent liveness bit.
// So we explicitly tell it which offset is in use.
- if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(R.Sec))
+ if (auto *MS = dyn_cast<MergeInputSection>(R.Sec))
MS->markLiveAt(R.Offset);
if (R.Sec->Live)
return;
R.Sec->Live = true;
// Add input section to the queue.
- if (InputSection<ELFT> *S = dyn_cast<InputSection<ELFT>>(R.Sec))
+ if (InputSection *S = dyn_cast<InputSection>(R.Sec))
Q.push_back(S);
};
auto MarkSymbol = [&](const SymbolBody *Sym) {
- if (auto *D = dyn_cast_or_null<DefinedRegular<ELFT>>(Sym))
- Enqueue({D->Section, D->Value});
+ if (auto *D = dyn_cast_or_null<DefinedRegular>(Sym))
+ Enqueue({cast<InputSectionBase>(D->Section), D->Value});
};
// Add GC root symbols.
@@ -234,14 +238,20 @@ template <class ELFT> void elf::markLive() {
// Preserve special sections and those which are specified in linker
// script KEEP command.
- for (InputSectionBase<ELFT> *Sec : Symtab<ELFT>::X->Sections) {
+ for (InputSectionBase *Sec : InputSections) {
// .eh_frame is always marked as live now, but also it can reference to
// sections that contain personality. We preserve all non-text sections
// referred by .eh_frame here.
- if (auto *EH = dyn_cast_or_null<EhInputSection<ELFT>>(Sec))
+ if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec))
scanEhFrameSection<ELFT>(*EH, Enqueue);
- if (isReserved(Sec) || Script<ELFT>::X->shouldKeep(Sec))
+ if (Sec->Flags & SHF_LINK_ORDER)
+ continue;
+ if (isReserved<ELFT>(Sec) || Script->shouldKeep(Sec))
Enqueue({Sec, 0});
+ else if (isValidCIdentifier(Sec->Name)) {
+ CNamedSections[Saver.save("__start_" + Sec->Name)].push_back(Sec);
+ CNamedSections[Saver.save("__end_" + Sec->Name)].push_back(Sec);
+ }
}
// Mark all reachable sections.
diff --git a/ELF/Options.td b/ELF/Options.td
index 77ed4c7e466f..7ed8dfb090bd 100644
--- a/ELF/Options.td
+++ b/ELF/Options.td
@@ -48,6 +48,8 @@ def color_diagnostics_eq: J<"color-diagnostics=">,
def define_common: F<"define-common">,
HelpText<"Assign space to common symbols">;
+def demangle: F<"demangle">, HelpText<"Demangle symbol names">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
@@ -68,6 +70,8 @@ def dynamic_list: S<"dynamic-list">,
def eh_frame_hdr: F<"eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
def enable_new_dtags: F<"enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
@@ -80,6 +84,9 @@ def entry: S<"entry">, MetaVarName<"<entry>">,
def error_limit: S<"error-limit">,
HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+def error_unresolved_symbols: F<"error-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as errors">;
+
def export_dynamic: F<"export-dynamic">,
HelpText<"Put symbols in the dynamic symbol table">;
@@ -124,6 +131,8 @@ def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">,
def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">;
+def Map: JS<"Map">, HelpText<"Print a link map to the specified file">;
+
def nostdlib: F<"nostdlib">,
HelpText<"Only search directories specified on the command line">;
@@ -139,6 +148,12 @@ def no_define_common: F<"no-define-common">,
def no_demangle: F<"no-demangle">,
HelpText<"Do not demangle symbol names">;
+def no_dynamic_linker: F<"no-dynamic-linker">,
+ HelpText<"Inhibit output of .interp section">;
+
+def no_export_dynamic: F<"no-export-dynamic">;
+def no_fatal_warnings: F<"no-fatal-warnings">;
+
def no_gc_sections: F<"no-gc-sections">,
HelpText<"Disable garbage collection of unused sections">;
@@ -170,7 +185,7 @@ def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">,
HelpText<"Specify the binary format for the output object file">;
-def omagic: F<"omagic">, MetaVarName<"<magic>">,
+def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">,
HelpText<"Set the text and data sections to be readable and writable">;
def pie: F<"pie">, HelpText<"Create a position independent executable">;
@@ -178,6 +193,9 @@ def pie: F<"pie">, HelpText<"Create a position independent executable">;
def print_gc_sections: F<"print-gc-sections">,
HelpText<"List removed unused sections">;
+def print_map: F<"print-map">,
+ HelpText<"Print a link map to the standard output">;
+
def reproduce: S<"reproduce">,
HelpText<"Dump linker invocation and input files for debugging">;
@@ -221,7 +239,7 @@ def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
def trace: F<"trace">, HelpText<"Print the names of the input files">;
-def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
+def trace_symbol : S<"trace-symbol">, HelpText<"Trace references to symbols">;
def undefined: S<"undefined">,
HelpText<"Force undefined symbol during linking">;
@@ -244,6 +262,9 @@ def version_script: S<"version-script">,
def warn_common: F<"warn-common">,
HelpText<"Warn about duplicate common symbols">;
+def warn_unresolved_symbols: F<"warn-unresolved-symbols">,
+ HelpText<"Report unresolved symbols as warnings">;
+
def whole_archive: F<"whole-archive">,
HelpText<"Force load of all members in a static library">;
@@ -267,6 +288,7 @@ def alias_define_common_dp: F<"dp">, Alias<define_common>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
+def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
def alias_entry_entry: J<"entry=">, Alias<entry>;
def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
@@ -278,10 +300,12 @@ def alias_format_b: S<"b">, Alias<format>;
def alias_hash_style_hash_style: J<"hash-style=">, Alias<hash_style>;
def alias_init_init: J<"init=">, Alias<init>;
def alias_l__library: J<"library=">, Alias<l>;
+def alias_Map_eq: J<"Map=">, Alias<Map>;
def alias_omagic: Flag<["-"], "N">, Alias<omagic>;
def alias_o_output: Joined<["--"], "output=">, Alias<o>;
def alias_o_output2 : Separate<["--"], "output">, Alias<o>;
def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;
+def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;
def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;
def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;
@@ -297,6 +321,7 @@ def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>;
def alias_Tbss: J<"Tbss=">, Alias<Tbss>;
def alias_Tdata: J<"Tdata=">, Alias<Tdata>;
def alias_trace: Flag<["-"], "t">, Alias<trace>;
+def trace_trace_symbol_eq : J<"trace-symbol=">, Alias<trace_symbol>;
def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>;
def alias_Ttext: J<"Ttext=">, Alias<Ttext>;
def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>;
@@ -329,17 +354,12 @@ def plugin_opt_eq: J<"plugin-opt=">;
// Options listed below are silently ignored for now for compatibility.
def allow_shlib_undefined: F<"allow-shlib-undefined">;
def cref: Flag<["--"], "cref">;
-def demangle: F<"demangle">;
def detect_odr_violations: F<"detect-odr-violations">;
def g: Flag<["-"], "g">;
-def M: Flag<["-"], "M">;
-def Map: JS<"Map">;
def no_add_needed: F<"no-add-needed">;
def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">;
def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">,
Alias<no_add_needed>;
-def no_dynamic_linker: F<"no-dynamic-linker">;
-def no_fatal_warnings: F<"no-fatal-warnings">;
def no_mmap_output_file: F<"no-mmap-output-file">;
def no_warn_common: F<"no-warn-common">;
def no_warn_mismatch: F<"no-warn-mismatch">;
@@ -355,7 +375,6 @@ def G: JoinedOrSeparate<["-"], "G">;
def Qy : F<"Qy">;
// Aliases for ignored options
-def alias_Map_eq: J<"Map=">, Alias<Map>;
def alias_version_script_version_script: J<"version-script=">,
Alias<version_script>;
@@ -368,5 +387,13 @@ def lto_partitions: J<"lto-partitions=">,
HelpText<"Number of LTO codegen partitions">;
def disable_verify: F<"disable-verify">;
def mllvm: S<"mllvm">;
+def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">,
+ HelpText<"YAML output file for optimization remarks">;
+def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
+ HelpText<"Include hotness informations in the optimization remarks file">;
def save_temps: F<"save-temps">;
+def thinlto_cache_dir: J<"thinlto-cache-dir=">,
+ HelpText<"Path to ThinLTO cached object file directory">;
+def thinlto_cache_policy: S<"thinlto-cache-policy">,
+ HelpText<"Pruning policy for the ThinLTO cache">;
def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">;
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp
index 7c708ce4ed67..93f83100a745 100644
--- a/ELF/OutputSections.cpp
+++ b/ELF/OutputSections.cpp
@@ -9,7 +9,6 @@
#include "OutputSections.h"
#include "Config.h"
-#include "EhFrame.h"
#include "LinkerScript.h"
#include "Memory.h"
#include "Strings.h"
@@ -31,15 +30,18 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-OutputSectionBase::OutputSectionBase(StringRef Name, uint32_t Type,
- uint64_t Flags)
- : Name(Name) {
- this->Type = Type;
- this->Flags = Flags;
- this->Addralign = 1;
-}
-
-uint32_t OutputSectionBase::getPhdrFlags() const {
+uint8_t Out::First;
+OutputSection *Out::Opd;
+uint8_t *Out::OpdBuf;
+PhdrEntry *Out::TlsPhdr;
+OutputSection *Out::DebugInfo;
+OutputSection *Out::ElfHeader;
+OutputSection *Out::ProgramHeaders;
+OutputSection *Out::PreinitArray;
+OutputSection *Out::InitArray;
+OutputSection *Out::FiniArray;
+
+uint32_t OutputSection::getPhdrFlags() const {
uint32_t Ret = PF_R;
if (Flags & SHF_WRITE)
Ret |= PF_W;
@@ -49,9 +51,9 @@ uint32_t OutputSectionBase::getPhdrFlags() const {
}
template <class ELFT>
-void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
+void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_entsize = Entsize;
- Shdr->sh_addralign = Addralign;
+ Shdr->sh_addralign = Alignment;
Shdr->sh_type = Type;
Shdr->sh_offset = Offset;
Shdr->sh_flags = Flags;
@@ -62,49 +64,28 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
Shdr->sh_name = ShName;
}
-template <class ELFT> static uint64_t getEntsize(uint32_t Type) {
- switch (Type) {
- case SHT_RELA:
- return sizeof(typename ELFT::Rela);
- case SHT_REL:
- return sizeof(typename ELFT::Rel);
- case SHT_MIPS_REGINFO:
- return sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_OPTIONS:
- return sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>);
- case SHT_MIPS_ABIFLAGS:
- return sizeof(Elf_Mips_ABIFlags<ELFT>);
- default:
- return 0;
- }
-}
-
-template <class ELFT>
-OutputSection<ELFT>::OutputSection(StringRef Name, uint32_t Type, uintX_t Flags)
- : OutputSectionBase(Name, Type, Flags) {
- this->Entsize = getEntsize<ELFT>(Type);
-}
+OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags)
+ : SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type,
+ /*Info*/ 0,
+ /*Link*/ 0) {}
-template <typename ELFT>
-static bool compareByFilePosition(InputSection<ELFT> *A,
- InputSection<ELFT> *B) {
+static bool compareByFilePosition(InputSection *A, InputSection *B) {
// Synthetic doesn't have link order dependecy, stable_sort will keep it last
- if (A->kind() == InputSectionData::Synthetic ||
- B->kind() == InputSectionData::Synthetic)
+ if (A->kind() == InputSectionBase::Synthetic ||
+ B->kind() == InputSectionBase::Synthetic)
return false;
- auto *LA = cast<InputSection<ELFT>>(A->getLinkOrderDep());
- auto *LB = cast<InputSection<ELFT>>(B->getLinkOrderDep());
- OutputSectionBase *AOut = LA->OutSec;
- OutputSectionBase *BOut = LB->OutSec;
+ auto *LA = cast<InputSection>(A->getLinkOrderDep());
+ auto *LB = cast<InputSection>(B->getLinkOrderDep());
+ OutputSection *AOut = LA->OutSec;
+ OutputSection *BOut = LB->OutSec;
if (AOut != BOut)
return AOut->SectionIndex < BOut->SectionIndex;
return LA->OutSecOff < LB->OutSecOff;
}
-template <class ELFT> void OutputSection<ELFT>::finalize() {
+template <class ELFT> void OutputSection::finalize() {
if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {
- std::sort(Sections.begin(), Sections.end(), compareByFilePosition<ELFT>);
- Size = 0;
+ std::sort(Sections.begin(), Sections.end(), compareByFilePosition);
assignOffsets();
// We must preserve the link order dependency of sections with the
@@ -116,34 +97,41 @@ template <class ELFT> void OutputSection<ELFT>::finalize() {
}
uint32_t Type = this->Type;
- if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
+ if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))
+ return;
+
+ InputSection *First = Sections[0];
+ if (isa<SyntheticSection>(First))
return;
this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
// sh_info for SHT_REL[A] sections should contain the section header index of
// the section to which the relocation applies.
- InputSectionBase<ELFT> *S = Sections[0]->getRelocatedSection();
+ InputSectionBase *S = First->getRelocatedSection();
this->Info = S->OutSec->SectionIndex;
}
-template <class ELFT>
-void OutputSection<ELFT>::addSection(InputSectionData *C) {
- assert(C->Live);
- auto *S = cast<InputSection<ELFT>>(C);
+void OutputSection::addSection(InputSection *S) {
+ assert(S->Live);
Sections.push_back(S);
S->OutSec = this;
this->updateAlignment(S->Alignment);
- // Keep sh_entsize value of the input section to be able to perform merging
- // later during a final linking using the generated relocatable object.
- if (Config->Relocatable && (S->Flags & SHF_MERGE))
- this->Entsize = S->Entsize;
+
+ // If this section contains a table of fixed-size entries, sh_entsize
+ // holds the element size. Consequently, if this contains two or more
+ // input sections, all of them must have the same sh_entsize. However,
+ // you can put different types of input sections into one output
+ // sectin by using linker scripts. I don't know what to do here.
+ // Probably we sholuld handle that as an error. But for now we just
+ // pick the largest sh_entsize.
+ this->Entsize = std::max(this->Entsize, S->Entsize);
}
// This function is called after we sort input sections
// and scan relocations to setup sections' offsets.
-template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
- uintX_t Off = this->Size;
- for (InputSection<ELFT> *S : Sections) {
+void OutputSection::assignOffsets() {
+ uint64_t Off = 0;
+ for (InputSection *S : Sections) {
Off = alignTo(Off, S->Alignment);
S->OutSecOff = Off;
Off += S->getSize();
@@ -151,14 +139,12 @@ template <class ELFT> void OutputSection<ELFT>::assignOffsets() {
this->Size = Off;
}
-template <class ELFT>
-void OutputSection<ELFT>::sort(
- std::function<int(InputSection<ELFT> *S)> Order) {
- typedef std::pair<unsigned, InputSection<ELFT> *> Pair;
+void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) {
+ typedef std::pair<unsigned, InputSection *> Pair;
auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; };
std::vector<Pair> V;
- for (InputSection<ELFT> *S : Sections)
+ for (InputSection *S : Sections)
V.push_back({Order(S), S});
std::stable_sort(V.begin(), V.end(), Comp);
Sections.clear();
@@ -172,9 +158,9 @@ void OutputSection<ELFT>::sort(
// because the compiler keeps the original initialization order in a
// translation unit and we need to respect that.
// For more detail, read the section of the GCC's manual about init_priority.
-template <class ELFT> void OutputSection<ELFT>::sortInitFini() {
+void OutputSection::sortInitFini() {
// Sort sections by priority.
- sort([](InputSection<ELFT> *S) { return getPriority(S->Name); });
+ sort([](InputSectionBase *S) { return getPriority(S->Name); });
}
// Returns true if S matches /Filename.?\.o$/.
@@ -208,15 +194,13 @@ static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); }
// .ctors are duplicate features (and .init_array is newer.) However, there
// are too many real-world use cases of .ctors, so we had no choice to
// support that with this rather ad-hoc semantics.
-template <class ELFT>
-static bool compCtors(const InputSection<ELFT> *A,
- const InputSection<ELFT> *B) {
- bool BeginA = isCrtbegin(A->getFile()->getName());
- bool BeginB = isCrtbegin(B->getFile()->getName());
+static bool compCtors(const InputSection *A, const InputSection *B) {
+ bool BeginA = isCrtbegin(A->File->getName());
+ bool BeginB = isCrtbegin(B->File->getName());
if (BeginA != BeginB)
return BeginA;
- bool EndA = isCrtend(A->getFile()->getName());
- bool EndB = isCrtend(B->getFile()->getName());
+ bool EndA = isCrtend(A->File->getName());
+ bool EndB = isCrtend(B->File->getName());
if (EndA != EndB)
return EndB;
StringRef X = A->Name;
@@ -233,319 +217,65 @@ static bool compCtors(const InputSection<ELFT> *A,
// Sorts input sections by the special rules for .ctors and .dtors.
// Unfortunately, the rules are different from the one for .{init,fini}_array.
// Read the comment above.
-template <class ELFT> void OutputSection<ELFT>::sortCtorsDtors() {
- std::stable_sort(Sections.begin(), Sections.end(), compCtors<ELFT>);
+void OutputSection::sortCtorsDtors() {
+ std::stable_sort(Sections.begin(), Sections.end(), compCtors);
}
-// Fill [Buf, Buf + Size) with Filler. Filler is written in big
-// endian order. This is used for linker script "=fillexp" command.
-void fill(uint8_t *Buf, size_t Size, uint32_t Filler) {
- uint8_t V[4];
- write32be(V, Filler);
+// 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) {
size_t I = 0;
for (; I + 4 < Size; I += 4)
- memcpy(Buf + I, V, 4);
- memcpy(Buf + I, V, Size - I);
-}
-
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Loc = Buf;
- if (uint32_t Filler = Script<ELFT>::X->getFiller(this->Name))
- fill(Buf, this->Size, Filler);
-
- auto Fn = [=](InputSection<ELFT> *IS) { IS->writeTo(Buf); };
- forEach(Sections.begin(), Sections.end(), Fn);
-
- // Linker scripts may have BYTE()-family commands with which you
- // can write arbitrary bytes to the output. Process them if any.
- Script<ELFT>::X->writeDataBytes(this->Name, Buf);
-}
-
-template <class ELFT>
-EhOutputSection<ELFT>::EhOutputSection()
- : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
-
-// Search for an existing CIE record or create a new one.
-// CIE records from input object files are uniquified by their contents
-// and where their relocations point to.
-template <class ELFT>
-template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- const endianness E = ELFT::TargetEndianness;
- if (read32<E>(Piece.data().data() + 4) != 0)
- fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
-
- SymbolBody *Personality = nullptr;
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI != (unsigned)-1)
- Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
-
- // Search for an existing CIE by CIE contents/relocation target pair.
- CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
-
- // If not found, create a new one.
- if (Cie->Piece == nullptr) {
- Cie->Piece = &Piece;
- Cies.push_back(Cie);
- }
- return Cie;
-}
-
-// There is one FDE per function. Returns true if a given FDE
-// points to a live function.
-template <class ELFT>
-template <class RelTy>
-bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
- ArrayRef<RelTy> Rels) {
- auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
- unsigned FirstRelI = Piece.FirstRelocation;
- if (FirstRelI == (unsigned)-1)
- fatal(toString(Sec) + ": FDE doesn't reference another section");
- const RelTy &Rel = Rels[FirstRelI];
- SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
- auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
- if (!D || !D->Section)
- return false;
- InputSectionBase<ELFT> *Target = D->Section->Repl;
- return Target && Target->Live;
-}
-
-// .eh_frame is a sequence of CIE or FDE records. In general, there
-// is one CIE record per input object file which is followed by
-// a list of FDEs. This function searches an existing CIE or create a new
-// one and associates FDEs to the CIE.
-template <class ELFT>
-template <class RelTy>
-void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> Rels) {
- const endianness E = ELFT::TargetEndianness;
-
- DenseMap<size_t, CieRecord *> OffsetToCie;
- for (EhSectionPiece &Piece : Sec->Pieces) {
- // The empty record is the end marker.
- if (Piece.size() == 4)
- return;
-
- size_t Offset = Piece.InputOff;
- uint32_t ID = read32<E>(Piece.data().data() + 4);
- if (ID == 0) {
- OffsetToCie[Offset] = addCie(Piece, Rels);
- continue;
- }
-
- uint32_t CieOffset = Offset + 4 - ID;
- CieRecord *Cie = OffsetToCie[CieOffset];
- if (!Cie)
- fatal(toString(Sec) + ": invalid CIE reference");
-
- if (!isFdeLive(Piece, Rels))
- continue;
- Cie->FdePieces.push_back(&Piece);
- NumFdes++;
- }
-}
-
-template <class ELFT>
-void EhOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<EhInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- Sections.push_back(Sec);
-
- // .eh_frame is a sequence of CIE or FDE records. This function
- // splits it into pieces so that we can call
- // SplitInputSection::getSectionPiece on the section.
- Sec->split();
- if (Sec->Pieces.empty())
- return;
-
- if (Sec->NumRelocations) {
- if (Sec->AreRelocsRela)
- addSectionAux(Sec, Sec->relas());
- else
- addSectionAux(Sec, Sec->rels());
- return;
- }
- addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
-}
-
-template <class ELFT>
-static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
- memcpy(Buf, D.data(), D.size());
-
- // Fix the size field. -4 since size does not include the size field itself.
- const endianness E = ELFT::TargetEndianness;
- write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
-}
-
-template <class ELFT> void EhOutputSection<ELFT>::finalize() {
- if (this->Size)
- return; // Already finalized.
-
- size_t Off = 0;
- for (CieRecord *Cie : Cies) {
- Cie->Piece->OutputOff = Off;
- Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- Fde->OutputOff = Off;
- Off += alignTo(Fde->size(), sizeof(uintX_t));
- }
- }
- this->Size = Off;
-}
-
-template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
- const endianness E = ELFT::TargetEndianness;
- switch (Size) {
- case DW_EH_PE_udata2:
- return read16<E>(Buf);
- case DW_EH_PE_udata4:
- return read32<E>(Buf);
- case DW_EH_PE_udata8:
- return read64<E>(Buf);
- case DW_EH_PE_absptr:
- if (ELFT::Is64Bits)
- return read64<E>(Buf);
- return read32<E>(Buf);
- }
- fatal("unknown FDE size encoding");
+ memcpy(Buf + I, &Filler, 4);
+ memcpy(Buf + I, &Filler, Size - I);
}
-// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
-// We need it to create .eh_frame_hdr section.
-template <class ELFT>
-typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
- uint8_t Enc) {
- // The starting address to which this FDE applies is
- // stored at FDE + 8 byte.
- size_t Off = FdeOff + 8;
- uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
- if ((Enc & 0x70) == DW_EH_PE_absptr)
- return Addr;
- if ((Enc & 0x70) == DW_EH_PE_pcrel)
- return Addr + this->Addr + Off;
- fatal("unknown FDE size relative encoding");
+uint32_t OutputSection::getFiller() {
+ // Determine what to fill gaps between InputSections with, as specified by the
+ // linker script. If nothing is specified and this is an executable section,
+ // fall back to trap instructions to prevent bad diassembly and detect invalid
+ // jumps to padding.
+ if (Optional<uint32_t> Filler = Script->getFiller(Name))
+ return *Filler;
+ if (Flags & SHF_EXECINSTR)
+ return Target->TrapInstr;
+ return 0;
}
-template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- const endianness E = ELFT::TargetEndianness;
- for (CieRecord *Cie : Cies) {
- size_t CieOffset = Cie->Piece->OutputOff;
- writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
-
- for (EhSectionPiece *Fde : Cie->FdePieces) {
- size_t Off = Fde->OutputOff;
- writeCieFde<ELFT>(Buf + Off, Fde->data());
-
- // FDE's second word should have the offset to an associated CIE.
- // Write it.
- write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
- }
- }
+template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) {
+ Loc = Buf;
- for (EhInputSection<ELFT> *S : Sections)
- S->relocate(Buf, nullptr);
-
- // Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
- // to get a FDE from an address to which FDE is applied. So here
- // we obtain two addresses and pass them to EhFrameHdr object.
- if (In<ELFT>::EhFrameHdr) {
- for (CieRecord *Cie : Cies) {
- uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
- for (SectionPiece *Fde : Cie->FdePieces) {
- uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
- uintX_t FdeVA = this->Addr + Fde->OutputOff;
- In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
- }
+ // Write leading padding.
+ uint32_t Filler = getFiller();
+ if (Filler)
+ fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler);
+
+ parallelFor(0, Sections.size(), [=](size_t I) {
+ InputSection *Sec = Sections[I];
+ Sec->writeTo<ELFT>(Buf);
+
+ // Fill gaps between sections.
+ if (Filler) {
+ uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize();
+ uint8_t *End;
+ if (I + 1 == Sections.size())
+ End = Buf + Size;
+ else
+ End = Buf + Sections[I + 1]->OutSecOff;
+ fill(Start, End - Start, Filler);
}
- }
-}
-
-template <class ELFT>
-MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t Type,
- uintX_t Flags, uintX_t Alignment)
- : OutputSectionBase(Name, Type, Flags),
- Builder(StringTableBuilder::RAW, Alignment) {}
-
-template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
- Builder.write(Buf);
-}
-
-template <class ELFT>
-void MergeOutputSection<ELFT>::addSection(InputSectionData *C) {
- auto *Sec = cast<MergeInputSection<ELFT>>(C);
- Sec->OutSec = this;
- this->updateAlignment(Sec->Alignment);
- this->Entsize = Sec->Entsize;
- Sections.push_back(Sec);
-}
-
-template <class ELFT> bool MergeOutputSection<ELFT>::shouldTailMerge() const {
- return (this->Flags & SHF_STRINGS) && Config->Optimize >= 2;
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Builder.add(Sec->getData(I));
-
- // Fix the string table content. After this, the contents will never change.
- Builder.finalize();
- this->Size = Builder.getSize();
-
- // finalize() fixed tail-optimized strings, so we can now get
- // offsets of strings. Get an offset for each string and save it
- // to a corresponding StringPiece for easy access.
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.getOffset(Sec->getData(I));
-}
+ });
-template <class ELFT> void MergeOutputSection<ELFT>::finalizeNoTailMerge() {
- // Add all string pieces to the string table builder to create section
- // contents. Because we are not tail-optimizing, offsets of strings are
- // fixed when they are added to the builder (string table builder contains
- // a hash table from strings to offsets).
- for (MergeInputSection<ELFT> *Sec : Sections)
- for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)
- if (Sec->Pieces[I].Live)
- Sec->Pieces[I].OutputOff = Builder.add(Sec->getData(I));
-
- Builder.finalizeInOrder();
- this->Size = Builder.getSize();
-}
-
-template <class ELFT> void MergeOutputSection<ELFT>::finalize() {
- if (shouldTailMerge())
- finalizeTailMerge();
- else
- finalizeNoTailMerge();
+ // Linker scripts may have BYTE()-family commands with which you
+ // can write arbitrary bytes to the output. Process them if any.
+ Script->writeDataBytes(Name, Buf);
}
-template <class ELFT>
-static typename ELFT::uint getOutFlags(InputSectionBase<ELFT> *S) {
+static uint64_t getOutFlags(InputSectionBase *S) {
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
}
-namespace llvm {
-template <> struct DenseMapInfo<lld::elf::SectionKey> {
- static lld::elf::SectionKey getEmptyKey();
- static lld::elf::SectionKey getTombstoneKey();
- static unsigned getHashValue(const lld::elf::SectionKey &Val);
- static bool isEqual(const lld::elf::SectionKey &LHS,
- const lld::elf::SectionKey &RHS);
-};
-}
-
-template <class ELFT>
-static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
+static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {
// The ELF spec just says
// ----------------------------------------------------------------
// In the first phase, input sections that match in name, type and
@@ -588,81 +318,76 @@ static SectionKey createKey(InputSectionBase<ELFT> *C, StringRef OutsecName) {
//
// Given the above issues, we instead merge sections by name and error on
// incompatible types and flags.
- //
- // The exception being SHF_MERGE, where we create different output sections
- // for each alignment. This makes each output section simple. In case of
- // relocatable object generation we do not try to perform merging and treat
- // SHF_MERGE sections as regular ones, but also create different output
- // sections for them to allow merging at final linking stage.
- //
- // Fortunately, creating symbols in the middle of a merge section is not
- // supported by bfd or gold, so the SHF_MERGE exception should not cause
- // problems with most linker scripts.
-
- typedef typename ELFT::uint uintX_t;
- uintX_t Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
- uintX_t Alignment = 0;
- if (isa<MergeInputSection<ELFT>>(C) ||
- (Config->Relocatable && (C->Flags & SHF_MERGE)))
- Alignment = std::max<uintX_t>(C->Alignment, C->Entsize);
+ uint32_t Alignment = 0;
+ uint64_t Flags = 0;
+ if (Config->Relocatable && (C->Flags & SHF_MERGE)) {
+ Alignment = std::max<uint64_t>(C->Alignment, C->Entsize);
+ Flags = C->Flags & (SHF_MERGE | SHF_STRINGS);
+ }
return SectionKey{OutsecName, Flags, Alignment};
}
-template <class ELFT> OutputSectionFactory<ELFT>::OutputSectionFactory() {}
+OutputSectionFactory::OutputSectionFactory(
+ std::vector<OutputSection *> &OutputSections)
+ : OutputSections(OutputSections) {}
-template <class ELFT> OutputSectionFactory<ELFT>::~OutputSectionFactory() {}
+static uint64_t getIncompatibleFlags(uint64_t Flags) {
+ return Flags & (SHF_ALLOC | SHF_TLS);
+}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(InputSectionBase<ELFT> *C,
- StringRef OutsecName) {
- SectionKey Key = createKey(C, OutsecName);
- return create(Key, C);
+// We allow sections of types listed below to merged into a
+// single progbits section. This is typically done by linker
+// scripts. Merging nobits and progbits will force disk space
+// to be allocated for nobits sections. Other ones don't require
+// any special treatment on top of progbits, so there doesn't
+// seem to be a harm in merging them.
+static bool canMergeToProgbits(unsigned Type) {
+ return Type == SHT_NOBITS || Type == SHT_PROGBITS || Type == SHT_INIT_ARRAY ||
+ Type == SHT_PREINIT_ARRAY || Type == SHT_FINI_ARRAY ||
+ Type == SHT_NOTE;
}
-static uint64_t getIncompatibleFlags(uint64_t Flags) {
- return Flags & (SHF_ALLOC | SHF_TLS);
+static void reportDiscarded(InputSectionBase *IS) {
+ if (!Config->PrintGcSections)
+ return;
+ message("removing unused section from '" + IS->Name + "' in file '" +
+ IS->File->getName());
}
-template <class ELFT>
-std::pair<OutputSectionBase *, bool>
-OutputSectionFactory<ELFT>::create(const SectionKey &Key,
- InputSectionBase<ELFT> *C) {
- uintX_t Flags = getOutFlags(C);
- OutputSectionBase *&Sec = Map[Key];
+void OutputSectionFactory::addInputSec(InputSectionBase *IS,
+ StringRef OutsecName) {
+ if (!IS->Live) {
+ reportDiscarded(IS);
+ return;
+ }
+
+ SectionKey Key = createKey(IS, OutsecName);
+ uint64_t Flags = getOutFlags(IS);
+ OutputSection *&Sec = Map[Key];
if (Sec) {
- if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(C->Flags))
+ if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))
error("Section has flags incompatible with others with the same name " +
- toString(C));
- // Convert notbits to progbits if they are mixed. This happens is some
- // linker scripts.
- if (Sec->Type == SHT_NOBITS && C->Type == SHT_PROGBITS)
- Sec->Type = SHT_PROGBITS;
- if (Sec->Type != C->Type &&
- !(Sec->Type == SHT_PROGBITS && C->Type == SHT_NOBITS))
- error("Section has different type from others with the same name " +
- toString(C));
+ toString(IS));
+ if (Sec->Type != IS->Type) {
+ if (canMergeToProgbits(Sec->Type) && canMergeToProgbits(IS->Type))
+ Sec->Type = SHT_PROGBITS;
+ else
+ error("Section has different type from others with the same name " +
+ toString(IS));
+ }
Sec->Flags |= Flags;
- return {Sec, false};
+ } else {
+ Sec = make<OutputSection>(Key.Name, IS->Type, Flags);
+ OutputSections.push_back(Sec);
}
- uint32_t Type = C->Type;
- switch (C->kind()) {
- case InputSectionBase<ELFT>::Regular:
- case InputSectionBase<ELFT>::Synthetic:
- Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
- break;
- case InputSectionBase<ELFT>::EHFrame:
- return {Out<ELFT>::EhFrame, false};
- case InputSectionBase<ELFT>::Merge:
- Sec = make<MergeOutputSection<ELFT>>(Key.Name, Type, Flags, Key.Alignment);
- break;
- }
- return {Sec, true};
+ Sec->addSection(cast<InputSection>(IS));
}
+OutputSectionFactory::~OutputSectionFactory() {}
+
SectionKey DenseMapInfo<SectionKey>::getEmptyKey() {
return SectionKey{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
}
@@ -681,32 +406,23 @@ bool DenseMapInfo<SectionKey>::isEqual(const SectionKey &LHS,
LHS.Flags == RHS.Flags && LHS.Alignment == RHS.Alignment;
}
-namespace lld {
-namespace elf {
-
-template void OutputSectionBase::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
-template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
-
-template class OutputSection<ELF32LE>;
-template class OutputSection<ELF32BE>;
-template class OutputSection<ELF64LE>;
-template class OutputSection<ELF64BE>;
-
-template class EhOutputSection<ELF32LE>;
-template class EhOutputSection<ELF32BE>;
-template class EhOutputSection<ELF64LE>;
-template class EhOutputSection<ELF64BE>;
-
-template class MergeOutputSection<ELF32LE>;
-template class MergeOutputSection<ELF32BE>;
-template class MergeOutputSection<ELF64LE>;
-template class MergeOutputSection<ELF64BE>;
-
-template class OutputSectionFactory<ELF32LE>;
-template class OutputSectionFactory<ELF32BE>;
-template class OutputSectionFactory<ELF64LE>;
-template class OutputSectionFactory<ELF64BE>;
-}
+uint64_t elf::getHeaderSize() {
+ if (Config->OFormatBinary)
+ return 0;
+ return Out::ElfHeader->Size + Out::ProgramHeaders->Size;
}
+
+template void OutputSection::writeHeaderTo<ELF32LE>(ELF32LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
+template void OutputSection::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
+
+template void OutputSection::finalize<ELF32LE>();
+template void OutputSection::finalize<ELF32BE>();
+template void OutputSection::finalize<ELF64LE>();
+template void OutputSection::finalize<ELF64BE>();
+
+template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf);
+template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf);
diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h
index 5c494bba977a..0ae3df5f7859 100644
--- a/ELF/OutputSections.h
+++ b/ELF/OutputSections.h
@@ -11,6 +11,7 @@
#define LLD_ELF_OUTPUT_SECTIONS_H
#include "Config.h"
+#include "InputSection.h"
#include "Relocations.h"
#include "lld/Core/LLVM.h"
@@ -23,49 +24,38 @@ namespace elf {
struct PhdrEntry;
class SymbolBody;
struct EhSectionPiece;
-template <class ELFT> class EhInputSection;
-template <class ELFT> class InputSection;
-template <class ELFT> class InputSectionBase;
-template <class ELFT> class MergeInputSection;
-template <class ELFT> class OutputSection;
+class EhInputSection;
+class InputSection;
+class InputSectionBase;
+class MergeInputSection;
+class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class SharedFile;
-template <class ELFT> class SharedSymbol;
-template <class ELFT> class DefinedRegular;
+class SharedSymbol;
+class DefinedRegular;
// This represents a section in an output file.
-// Different sub classes represent different types of sections. Some contain
-// input sections, others are created by the linker.
+// It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
-class OutputSectionBase {
+class OutputSection final : public SectionBase {
public:
- enum Kind {
- Base,
- EHFrame,
- Merge,
- Regular,
- };
+ OutputSection(StringRef Name, uint32_t Type, uint64_t Flags);
+
+ static bool classof(const SectionBase *S) {
+ return S->kind() == SectionBase::Output;
+ }
- OutputSectionBase(StringRef Name, uint32_t Type, uint64_t Flags);
- void setLMAOffset(uint64_t LMAOff) { LMAOffset = LMAOff; }
uint64_t getLMA() const { return Addr + LMAOffset; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr);
- StringRef getName() const { return Name; }
-
- virtual void addSection(InputSectionData *C) {}
- virtual Kind getKind() const { return Base; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Base;
- }
unsigned SectionIndex;
uint32_t getPhdrFlags() const;
- void updateAlignment(uint64_t Alignment) {
- if (Alignment > Addralign)
- Addralign = Alignment;
+ void updateAlignment(uint32_t Val) {
+ if (Val > Alignment)
+ Alignment = Val;
}
// If true, this section will be page aligned on disk.
@@ -78,191 +68,82 @@ public:
// between their file offsets should be equal to difference between their
// virtual addresses. To compute some section offset we use the following
// formula: Off = Off_first + VA - VA_first.
- OutputSectionBase *FirstInPtLoad = nullptr;
-
- virtual void finalize() {}
- virtual void assignOffsets() {}
- virtual void writeTo(uint8_t *Buf) {}
- virtual ~OutputSectionBase() = default;
-
- StringRef Name;
+ OutputSection *FirstInPtLoad = nullptr;
// The following fields correspond to Elf_Shdr members.
uint64_t Size = 0;
- uint64_t Entsize = 0;
- uint64_t Addralign = 0;
uint64_t Offset = 0;
- uint64_t Flags = 0;
uint64_t LMAOffset = 0;
uint64_t Addr = 0;
uint32_t ShName = 0;
- uint32_t Type = 0;
- uint32_t Info = 0;
- uint32_t Link = 0;
-};
-
-template <class ELFT> class OutputSection final : public OutputSectionBase {
-public:
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Sym Elf_Sym;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
- typedef typename ELFT::uint uintX_t;
- OutputSection(StringRef Name, uint32_t Type, uintX_t Flags);
- void addSection(InputSectionData *C) override;
- void sort(std::function<int(InputSection<ELFT> *S)> Order);
+ void addSection(InputSection *S);
+ void sort(std::function<int(InputSectionBase *S)> Order);
void sortInitFini();
void sortCtorsDtors();
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- void assignOffsets() override;
- Kind getKind() const override { return Regular; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Regular;
- }
- std::vector<InputSection<ELFT> *> Sections;
+ uint32_t getFiller();
+ template <class ELFT> void writeTo(uint8_t *Buf);
+ template <class ELFT> void finalize();
+ void assignOffsets();
+ std::vector<InputSection *> Sections;
// Location in the output buffer.
uint8_t *Loc = nullptr;
};
-template <class ELFT>
-class MergeOutputSection final : public OutputSectionBase {
- typedef typename ELFT::uint uintX_t;
-
-public:
- MergeOutputSection(StringRef Name, uint32_t Type, uintX_t Flags,
- uintX_t Alignment);
- void addSection(InputSectionData *S) override;
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- bool shouldTailMerge() const;
- Kind getKind() const override { return Merge; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == Merge;
- }
-
-private:
- void finalizeTailMerge();
- void finalizeNoTailMerge();
-
- llvm::StringTableBuilder Builder;
- std::vector<MergeInputSection<ELFT> *> Sections;
-};
-
-struct CieRecord {
- EhSectionPiece *Piece = nullptr;
- std::vector<EhSectionPiece *> FdePieces;
-};
-
-// Output section for .eh_frame.
-template <class ELFT> class EhOutputSection final : public OutputSectionBase {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::Rel Elf_Rel;
- typedef typename ELFT::Rela Elf_Rela;
-
-public:
- EhOutputSection();
- void writeTo(uint8_t *Buf) override;
- void finalize() override;
- bool empty() const { return Sections.empty(); }
-
- void addSection(InputSectionData *S) override;
- Kind getKind() const override { return EHFrame; }
- static bool classof(const OutputSectionBase *B) {
- return B->getKind() == EHFrame;
- }
-
- size_t NumFdes = 0;
-
-private:
- template <class RelTy>
- void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
-
- template <class RelTy>
- CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
-
- template <class RelTy>
- bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
-
- uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
-
- std::vector<EhInputSection<ELFT> *> Sections;
- std::vector<CieRecord *> Cies;
-
- // CIE records are uniquified by their contents and personality functions.
- llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
-};
-
-// All output sections that are hadnled by the linker specially are
+// All output sections that are handled by the linker specially are
// globally accessible. Writer initializes them, so don't use them
// until Writer is initialized.
-template <class ELFT> struct Out {
- typedef typename ELFT::uint uintX_t;
- typedef typename ELFT::Phdr Elf_Phdr;
-
+struct Out {
static uint8_t First;
- static EhOutputSection<ELFT> *EhFrame;
- static OutputSection<ELFT> *Bss;
- static OutputSection<ELFT> *BssRelRo;
- static OutputSectionBase *Opd;
+ static OutputSection *Opd;
static uint8_t *OpdBuf;
static PhdrEntry *TlsPhdr;
- static OutputSectionBase *DebugInfo;
- static OutputSectionBase *ElfHeader;
- static OutputSectionBase *ProgramHeaders;
- static OutputSectionBase *PreinitArray;
- static OutputSectionBase *InitArray;
- static OutputSectionBase *FiniArray;
+ static OutputSection *DebugInfo;
+ static OutputSection *ElfHeader;
+ static OutputSection *ProgramHeaders;
+ static OutputSection *PreinitArray;
+ static OutputSection *InitArray;
+ static OutputSection *FiniArray;
};
struct SectionKey {
StringRef Name;
uint64_t Flags;
- uint64_t Alignment;
+ uint32_t Alignment;
+};
+}
+}
+namespace llvm {
+template <> struct DenseMapInfo<lld::elf::SectionKey> {
+ static lld::elf::SectionKey getEmptyKey();
+ static lld::elf::SectionKey getTombstoneKey();
+ static unsigned getHashValue(const lld::elf::SectionKey &Val);
+ static bool isEqual(const lld::elf::SectionKey &LHS,
+ const lld::elf::SectionKey &RHS);
};
+}
+namespace lld {
+namespace elf {
// This class knows how to create an output section for a given
// input section. Output section type is determined by various
// factors, including input section's sh_flags, sh_type and
// linker scripts.
-template <class ELFT> class OutputSectionFactory {
- typedef typename ELFT::Shdr Elf_Shdr;
- typedef typename ELFT::uint uintX_t;
-
+class OutputSectionFactory {
public:
- OutputSectionFactory();
+ OutputSectionFactory(std::vector<OutputSection *> &OutputSections);
~OutputSectionFactory();
- std::pair<OutputSectionBase *, bool> create(InputSectionBase<ELFT> *C,
- StringRef OutsecName);
- std::pair<OutputSectionBase *, bool> create(const SectionKey &Key,
- InputSectionBase<ELFT> *C);
+
+ void addInputSec(InputSectionBase *IS, StringRef OutsecName);
private:
- llvm::SmallDenseMap<SectionKey, OutputSectionBase *> Map;
+ llvm::SmallDenseMap<SectionKey, OutputSection *> Map;
+ std::vector<OutputSection *> &OutputSections;
};
-template <class ELFT> uint64_t getHeaderSize() {
- if (Config->OFormatBinary)
- return 0;
- return Out<ELFT>::ElfHeader->Size + Out<ELFT>::ProgramHeaders->Size;
-}
+uint64_t getHeaderSize();
-template <class ELFT> uint8_t Out<ELFT>::First;
-template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
-template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
-template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
-template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
-template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
-template <class ELFT> PhdrEntry *Out<ELFT>::TlsPhdr;
-template <class ELFT> OutputSectionBase *Out<ELFT>::DebugInfo;
-template <class ELFT> OutputSectionBase *Out<ELFT>::ElfHeader;
-template <class ELFT> OutputSectionBase *Out<ELFT>::ProgramHeaders;
-template <class ELFT> OutputSectionBase *Out<ELFT>::PreinitArray;
-template <class ELFT> OutputSectionBase *Out<ELFT>::InitArray;
-template <class ELFT> OutputSectionBase *Out<ELFT>::FiniArray;
} // namespace elf
} // namespace lld
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index cecd11e90790..baef0a2f2257 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -43,6 +43,7 @@
#include "Relocations.h"
#include "Config.h"
+#include "Memory.h"
#include "OutputSections.h"
#include "Strings.h"
#include "SymbolTable.h"
@@ -52,20 +53,30 @@
#include "llvm/Support/Endian.h"
#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;
using namespace llvm::support::endian;
-namespace lld {
-namespace elf {
+using namespace lld;
+using namespace lld::elf;
-static bool refersToGotEntry(RelExpr Expr) {
- return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF,
- R_MIPS_GOT_OFF32, R_MIPS_TLSGD, R_MIPS_TLSLD,
- R_GOT_PAGE_PC, R_GOT_PC, R_GOT_FROM_END, R_TLSGD,
- R_TLSGD_PC, R_TLSDESC, R_TLSDESC_PAGE>(Expr);
+// Construct a message in the following format.
+//
+// >>> defined in /home/alice/src/foo.o
+// >>> referenced by bar.c:12 (/home/alice/src/bar.c:12)
+// >>> /home/alice/src/bar.o:(.text+0x1)
+template <class ELFT>
+static std::string getLocation(InputSectionBase &S, const SymbolBody &Sym,
+ uint64_t Off) {
+ std::string Msg =
+ "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by ";
+ std::string Src = S.getSrcMsg<ELFT>(Off);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ return Msg + S.getObjMsg<ELFT>(Off);
}
static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
@@ -84,44 +95,92 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) {
return Body.isPreemptible();
}
-// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not
-// support any relaxations for TLS relocations so by factoring out ARM and MIPS
+// This function is similar to the `handleTlsRelocation`. MIPS does not
+// support any relaxations for TLS relocations so by factoring out MIPS
// handling in to the separate function we can simplify the code and do not
-// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements.
-template <class ELFT, class GOT>
-static unsigned handleNoRelaxTlsRelocation(
- GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase<ELFT> &C,
- typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) {
- typedef typename ELFT::uint uintX_t;
- auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_t Off, bool LD) {
- // The Dynamic TLS Module Index Relocation can be statically resolved to 1
- // if we know that we are linking an executable. For ARM we resolve the
- // relocation when writing the Got. MIPS has a custom Got implementation
- // that writes the Module index in directly.
- if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM)
- Got->Relocations.push_back(
- {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body});
- else {
- SymbolBody *Dest = LD ? nullptr : &Body;
+// pollute other `handleTlsRelocation` by MIPS `ifs` statements.
+// Mips has a custom MipsGotSection that handles the writing of GOT entries
+// without dynamic relocations.
+template <class ELFT>
+static unsigned handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ if (Expr == R_MIPS_TLSLD) {
+ if (In<ELFT>::MipsGot->addTlsIndex() && Config->Pic)
+ In<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, In<ELFT>::MipsGot,
+ In<ELFT>::MipsGot->getTlsIndexOff(), false,
+ nullptr, 0});
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ return 1;
+ }
+
+ if (Expr == R_MIPS_TLSGD) {
+ if (In<ELFT>::MipsGot->addDynTlsEntry(Body) && Body.isPreemptible()) {
+ uint64_t Off = In<ELFT>::MipsGot->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
- {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0});
+ {Target->TlsModuleIndexRel, In<ELFT>::MipsGot, Off, false, &Body, 0});
+ if (Body.isPreemptible())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::MipsGot,
+ Off + Config->Wordsize, false, &Body, 0});
}
+ C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
+ return 1;
+ }
+ return 0;
+}
+
+// This function is similar to the `handleMipsTlsRelocation`. ARM also does not
+// support any relaxations for TLS relocations. ARM is logically similar to Mips
+// in how it handles TLS, but Mips uses its own custom GOT which handles some
+// of the cases that ARM uses GOT relocations for.
+//
+// We look for TLS global dynamic and local dynamic relocations, these may
+// require the generation of a pair of GOT entries that have associated
+// dynamic relocations. When the results of the dynamic relocations can be
+// resolved at static link time we do so. This is necessary for static linking
+// as there will be no dynamic loader to resolve them at load-time.
+//
+// The pair of GOT entries created are of the form
+// GOT[e0] Module Index (Used to find pointer to TLS block at run-time)
+// GOT[e1] Offset of symbol in TLS block
+template <class ELFT>
+static unsigned handleARMTlsRelocation(uint32_t Type, SymbolBody &Body,
+ InputSectionBase &C, uint64_t Offset,
+ int64_t Addend, RelExpr Expr) {
+ // The Dynamic TLS Module Index Relocation for a symbol defined in an
+ // executable is always 1. If the target Symbol is not preemtible then
+ // we know the offset into the TLS block at static link time.
+ bool NeedDynId = Body.isPreemptible() || Config->Shared;
+ bool NeedDynOff = Body.isPreemptible();
+
+ auto AddTlsReloc = [&](uint64_t Off, uint32_t Type, SymbolBody *Dest,
+ bool Dyn) {
+ if (Dyn)
+ In<ELFT>::RelaDyn->addReloc({Type, In<ELFT>::Got, Off, false, Dest, 0});
+ else
+ In<ELFT>::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest});
};
- if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) {
- if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM))
- addModuleReloc(Body, Got, Got->getTlsIndexOff(), true);
+
+ // 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 && In<ELFT>::Got->addTlsIndex()) {
+ AddTlsReloc(In<ELFT>::Got->getTlsIndexOff(), Target->TlsModuleIndexRel,
+ NeedDynId ? nullptr : &Body, NeedDynId);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
}
- if (Target->isTlsGlobalDynamicRel(Type)) {
- if (Got->addDynTlsEntry(Body) &&
- (Body.isPreemptible() || Config->EMachine == EM_ARM)) {
- uintX_t Off = Got->getGlobalDynOffset(Body);
- addModuleReloc(Body, Got, Off, false);
- if (Body.isPreemptible())
- In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Got,
- Off + (uintX_t)sizeof(uintX_t), false,
- &Body, 0});
+
+ // Global Dynamic is the most general purpose access model. When we know
+ // 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 (In<ELFT>::Got->addDynTlsEntry(Body)) {
+ uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ AddTlsReloc(Off, Target->TlsModuleIndexRel, &Body, NeedDynId);
+ AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Body,
+ NeedDynOff);
}
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
return 1;
@@ -131,30 +190,25 @@ static unsigned handleNoRelaxTlsRelocation(
// Returns the number of relocations processed.
template <class ELFT>
-static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
- InputSectionBase<ELFT> &C,
- typename ELFT::uint Offset,
- typename ELFT::uint Addend, RelExpr Expr) {
+static unsigned
+handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C,
+ typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) {
if (!(C.Flags & SHF_ALLOC))
return 0;
if (!Body.isTls())
return 0;
- typedef typename ELFT::uint uintX_t;
-
if (Config->EMachine == EM_ARM)
- return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::Got, Type, Body, C,
- Offset, Addend, Expr);
+ return handleARMTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
if (Config->EMachine == EM_MIPS)
- return handleNoRelaxTlsRelocation<ELFT>(In<ELFT>::MipsGot, Type, Body, C,
- Offset, Addend, Expr);
+ return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr);
bool IsPreemptible = isPreemptible(Body, Type);
- if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) &&
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) &&
Config->Shared) {
if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc({Target->TlsDescRel, In<ELFT>::Got, Off,
!IsPreemptible, &Body, 0});
}
@@ -163,7 +217,7 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
return 1;
}
- if (Expr == R_TLSLD_PC || Expr == R_TLSLD) {
+ if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
C.Relocations.push_back(
@@ -185,17 +239,17 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
return 1;
}
- if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL ||
- Target->isTlsGlobalDynamicRel(Type)) {
+ if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD,
+ R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (In<ELFT>::Got->addDynTlsEntry(Body)) {
- uintX_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
+ uint64_t Off = In<ELFT>::Got->getGlobalDynOffset(Body);
In<ELFT>::RelaDyn->addReloc(
{Target->TlsModuleIndexRel, In<ELFT>::Got, Off, false, &Body, 0});
// If the symbol is preemptible we need the dynamic linker to write
// the offset too.
- uintX_t OffsetOff = Off + (uintX_t)sizeof(uintX_t);
+ uint64_t OffsetOff = Off + Config->Wordsize;
if (IsPreemptible)
In<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, In<ELFT>::Got,
OffsetOff, false, &Body, 0});
@@ -216,14 +270,13 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
if (!Body.isInGot()) {
In<ELFT>::Got->addEntry(Body);
In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::Got,
- Body.getGotOffset<ELFT>(), false, &Body,
- 0});
+ Body.getGotOffset(), false, &Body, 0});
}
- return Target->TlsGdRelaxSkip;
+ } else {
+ C.Relocations.push_back(
+ {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
+ Offset, Addend, &Body});
}
- C.Relocations.push_back(
- {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type,
- Offset, Addend, &Body});
return Target->TlsGdRelaxSkip;
}
@@ -234,16 +287,14 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body,
{R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body});
return 1;
}
- return 0;
-}
-template <endianness E> static int16_t readSignedLo16(const uint8_t *Loc) {
- return read32<E>(Loc) & 0xffff;
+ if (Expr == R_TLSDESC_CALL)
+ return 1;
+ return 0;
}
-template <class RelTy>
-static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
- switch (Rel->getType(Config->Mips64EL)) {
+static uint32_t getMipsPairType(uint32_t Type, const SymbolBody &Sym) {
+ switch (Type) {
case R_MIPS_HI16:
return R_MIPS_LO16;
case R_MIPS_GOT16:
@@ -257,72 +308,60 @@ static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) {
}
}
-template <class ELFT, class RelTy>
-static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc,
- SymbolBody &Sym, const RelTy *Rel,
- const RelTy *End) {
- uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL);
- uint32_t Type = getMipsPairType(Rel, Sym);
-
- // Some MIPS relocations use addend calculated from addend of the relocation
- // itself and addend of paired relocation. ABI requires to compute such
- // combined addend in case of REL relocation record format only.
- // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- if (RelTy::IsRela || Type == R_MIPS_NONE)
- return 0;
-
- for (const RelTy *RI = Rel; RI != End; ++RI) {
- if (RI->getType(Config->Mips64EL) != Type)
- continue;
- if (RI->getSymbol(Config->Mips64EL) != SymIndex)
- continue;
- const endianness E = ELFT::TargetEndianness;
- return ((read32<E>(BufLoc) & 0xffff) << 16) +
- readSignedLo16<E>(Buf + RI->r_offset);
- }
- warn("can't find matching " + toString(Type) + " relocation for " +
- toString(Rel->getType(Config->Mips64EL)));
- return 0;
-}
-
// True if non-preemptable symbol always has the same value regardless of where
// the DSO is loaded.
-template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
+static bool isAbsolute(const SymbolBody &Body) {
if (Body.isUndefined())
return !Body.isLocal() && Body.symbol()->isWeak();
- if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(&Body))
+ if (const auto *DR = dyn_cast<DefinedRegular>(&Body))
return DR->Section == nullptr; // Absolute symbol.
return false;
}
-template <class ELFT> static bool isAbsoluteValue(const SymbolBody &Body) {
- return isAbsolute<ELFT>(Body) || Body.isTls();
+static bool isAbsoluteValue(const SymbolBody &Body) {
+ return isAbsolute(Body) || Body.isTls();
}
+// Returns true if Expr refers a PLT entry.
static bool needsPlt(RelExpr Expr) {
- return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC,
- R_THUNK_PLT_PC>(Expr);
+ return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(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);
}
// 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_PAGE_PC, R_RELAX_GOT_PC, R_THUNK_PC, R_THUNK_PLT_PC>(
- Expr);
+ R_PAGE_PC, R_RELAX_GOT_PC>(Expr);
}
+// Returns true if a given relocation can be computed at link-time.
+//
+// For instance, we know the offset from a relocation to its target at
+// link-time if the relocation is PC-relative and refers a
+// non-interposable function in the same executable. This function
+// will return true for such relocation.
+//
+// If this function returns false, that means we need to emit a
+// dynamic relocation so that the relocation will be fixed at load-time.
template <class ELFT>
static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
const SymbolBody &Body,
- InputSectionBase<ELFT> &S,
- typename ELFT::uint RelOff) {
+ InputSectionBase &S, uint64_t RelOff) {
// These expressions always compute a constant
if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE,
- R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_TLSGD,
- R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC, R_TLSGD_PC, R_TLSGD,
- R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT,
- R_THUNK_PC, R_THUNK_PLT_PC>(E))
+ R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC,
+ R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_PLT_PC,
+ R_TLSGD_PC, R_TLSGD, R_PPC_PLT_OPD, R_TLSDESC_CALL,
+ R_TLSDESC_PAGE, R_HINT>(E))
return true;
// These never do, except if the entire file is position dependent or if
@@ -332,16 +371,19 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
if (isPreemptible(Body, Type))
return false;
-
if (!Config->Pic)
return true;
- bool AbsVal = isAbsoluteValue<ELFT>(Body);
+ // For the target and the relocation, we want to know if they are
+ // absolute or relative.
+ bool AbsVal = isAbsoluteValue(Body);
bool RelE = isRelExpr(E);
if (AbsVal && !RelE)
return true;
if (!AbsVal && RelE)
return true;
+ if (!AbsVal && !RelE)
+ return Target->usesOnlyLowPageBits(Type);
// Relative relocation to an absolute value. This is normally unrepresentable,
// but if the relocation refers to a weak undefined symbol, we allow it to
@@ -351,18 +393,13 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
// Another special case is MIPS _gp_disp symbol which represents offset
// between start of a function and '_gp' value and defined as absolute just
// to simplify the code.
- if (AbsVal && RelE) {
- if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
- return true;
- if (&Body == ElfSym<ELFT>::MipsGpDisp)
- return true;
- error(S.getLocation(RelOff) + ": relocation " + toString(Type) +
- " cannot refer to absolute symbol '" + toString(Body) +
- "' defined in " + toString(Body.File));
+ assert(AbsVal && RelE);
+ if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak())
return true;
- }
- return Target->usesOnlyLowPageBits(Type);
+ error("relocation " + toString(Type) + " cannot refer to absolute symbol: " +
+ toString(Body) + getLocation<ELFT>(S, Body, RelOff));
+ return true;
}
static RelExpr toPlt(RelExpr Expr) {
@@ -389,23 +426,14 @@ static RelExpr fromPlt(RelExpr Expr) {
return Expr;
}
-template <class ELFT> static uint32_t getAlignment(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
-
- uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign;
- uintX_t SymValue = SS->Sym.st_value;
- int TrailingZeros =
- std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue));
- return 1 << TrailingZeros;
-}
-
-template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
+// Returns true if a given shared symbol is in a read-only segment in a DSO.
+template <class ELFT> static bool isReadOnly(SharedSymbol *SS) {
typedef typename ELFT::Phdr Elf_Phdr;
+ uint64_t Value = SS->getValue<ELFT>();
// Determine if the symbol is read-only by scanning the DSO's program headers.
- uintX_t Value = SS->Sym.st_value;
- for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers()))
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+ for (const Elf_Phdr &Phdr : check(File->getObj().program_headers()))
if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) &&
!(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr &&
Value < Phdr.p_vaddr + Phdr.p_memsz)
@@ -413,62 +441,112 @@ template <class ELFT> static bool isReadOnly(SharedSymbol<ELFT> *SS) {
return false;
}
-// Reserve space in .bss or .bss.rel.ro for copy relocation.
-template <class ELFT> static void addCopyRelSymbol(SharedSymbol<ELFT> *SS) {
- typedef typename ELFT::uint uintX_t;
+// Returns symbols at the same offset as a given symbol, including SS itself.
+//
+// If two or more symbols are at the same offset, and at least one of
+// them are copied by a copy relocation, all of them need to be copied.
+// Otherwise, they would refer different places at runtime.
+template <class ELFT>
+static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) {
typedef typename ELFT::Sym Elf_Sym;
+ auto *File = cast<SharedFile<ELFT>>(SS->File);
+ uint64_t Shndx = SS->getShndx<ELFT>();
+ uint64_t Value = SS->getValue<ELFT>();
+
+ std::vector<SharedSymbol *> Ret;
+ for (const Elf_Sym &S : File->getGlobalSymbols()) {
+ if (S.st_shndx != Shndx || S.st_value != Value)
+ continue;
+ StringRef Name = check(S.getName(File->getStringTable()));
+ SymbolBody *Sym = Symtab<ELFT>::X->find(Name);
+ if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym))
+ Ret.push_back(Alias);
+ }
+ return Ret;
+}
+
+// Reserve space in .bss or .bss.rel.ro for copy relocation.
+//
+// The copy relocation is pretty much a hack. If you use a copy relocation
+// in your program, not only the symbol name but the symbol's size, RW/RO
+// bit and alignment become part of the ABI. In addition to that, if the
+// symbol has aliases, the aliases become part of the ABI. That's subtle,
+// but if you violate that implicit ABI, that can cause very counter-
+// intuitive consequences.
+//
+// So, what is the copy relocation? It's for linking non-position
+// independent code to DSOs. In an ideal world, all references to data
+// exported by DSOs should go indirectly through GOT. But if object files
+// are compiled as non-PIC, all data references are direct. There is no
+// way for the linker to transform the code to use GOT, as machine
+// instructions are already set in stone in object files. This is where
+// the copy relocation takes a role.
+//
+// A copy relocation instructs the dynamic linker to copy data from a DSO
+// to a specified address (which is usually in .bss) at load-time. If the
+// static linker (that's us) finds a direct data reference to a DSO
+// symbol, it creates a copy relocation, so that the symbol can be
+// resolved as if it were in .bss rather than in a DSO.
+//
+// As you can see in this function, we create a copy relocation for the
+// dynamic linker, and the relocation contains not only symbol name but
+// various other informtion about the symbol. So, such attributes become a
+// part of the ABI.
+//
+// Note for application developers: I can give you a piece of advice if
+// you are writing a shared library. You probably should export only
+// functions from your library. You shouldn't export variables.
+//
+// As an example what can happen when you export variables without knowing
+// the semantics of copy relocations, assume that you have an exported
+// variable of type T. It is an ABI-breaking change to add new members at
+// end of T even though doing that doesn't change the layout of the
+// existing members. That's because the space for the new members are not
+// reserved in .bss unless you recompile the main program. That means they
+// are likely to overlap with other data that happens to be laid out next
+// to the variable in .bss. This kind of issue is sometimes very hard to
+// debug. What's a solution? Instead of exporting a varaible V from a DSO,
+// define an accessor getV().
+template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) {
// Copy relocation against zero-sized symbol doesn't make sense.
- uintX_t SymSize = SS->template getSize<ELFT>();
+ uint64_t SymSize = SS->template getSize<ELFT>();
if (SymSize == 0)
fatal("cannot create a copy relocation for symbol " + toString(*SS));
// See if this symbol is in a read-only segment. If so, preserve the symbol's
// memory protection by reserving space in the .bss.rel.ro section.
- bool IsReadOnly = isReadOnly(SS);
- OutputSection<ELFT> *CopySec =
- IsReadOnly ? Out<ELFT>::BssRelRo : Out<ELFT>::Bss;
-
- uintX_t Alignment = getAlignment(SS);
- uintX_t Off = alignTo(CopySec->Size, Alignment);
- CopySec->Size = Off + SymSize;
- CopySec->updateAlignment(Alignment);
- uintX_t Shndx = SS->Sym.st_shndx;
- uintX_t Value = SS->Sym.st_value;
+ bool IsReadOnly = isReadOnly<ELFT>(SS);
+ BssSection *Sec = IsReadOnly ? In<ELFT>::BssRelRo : In<ELFT>::Bss;
+ uint64_t Off = Sec->reserveSpace(SymSize, SS->getAlignment<ELFT>());
+
// Look through the DSO's dynamic symbol table for aliases and create a
// dynamic symbol for each one. This causes the copy relocation to correctly
// interpose any aliases.
- for (const Elf_Sym &S : SS->file()->getGlobalSymbols()) {
- if (S.st_shndx != Shndx || S.st_value != Value)
- continue;
- auto *Alias = dyn_cast_or_null<SharedSymbol<ELFT>>(
- Symtab<ELFT>::X->find(check(S.getName(SS->file()->getStringTable()))));
- if (!Alias)
- continue;
- Alias->CopyIsInBssRelRo = IsReadOnly;
- Alias->CopyOffset = Off;
- Alias->NeedsCopyOrPltAddr = true;
- Alias->symbol()->IsUsedInRegularObj = true;
+ for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) {
+ Sym->NeedsCopy = true;
+ Sym->CopyRelSec = Sec;
+ Sym->CopyRelSecOff = Off;
+ Sym->symbol()->IsUsedInRegularObj = true;
}
- In<ELFT>::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, false, SS, 0});
+
+ In<ELFT>::RelaDyn->addReloc({Target->CopyRel, Sec, Off, false, SS, 0});
}
template <class ELFT>
-static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
- bool IsWrite, RelExpr Expr, uint32_t Type,
- const uint8_t *Data, InputSectionBase<ELFT> &S,
+static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type,
+ const uint8_t *Data, InputSectionBase &S,
typename ELFT::uint RelOff) {
- bool Preemptible = isPreemptible(Body, Type);
if (Body.isGnuIFunc()) {
Expr = toPlt(Expr);
- } else if (!Preemptible) {
+ } else if (!isPreemptible(Body, Type)) {
if (needsPlt(Expr))
Expr = fromPlt(Expr);
- if (Expr == R_GOT_PC && !isAbsoluteValue<ELFT>(Body))
+ if (Expr == R_GOT_PC && !isAbsoluteValue(Body))
Expr = Target->adjustRelaxExpr(Type, Data, Expr);
}
- Expr = Target->getThunkExpr(Expr, Type, File, Body);
+ bool IsWrite = !Config->ZText || (S.Flags & SHF_WRITE);
if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, S, RelOff))
return Expr;
@@ -476,25 +554,34 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
// only memory. We can hack around it if we are producing an executable and
// the refered symbol can be preemepted to refer to the executable.
if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) {
- error(S.getLocation(RelOff) + ": can't create dynamic relocation " +
- toString(Type) + " against " +
+ error("can't create dynamic relocation " + toString(Type) + " against " +
(Body.getName().empty() ? "local symbol in readonly segment"
- : "symbol '" + toString(Body) + "'") +
- " defined in " + toString(Body.File));
+ : "symbol: " + toString(Body)) +
+ getLocation<ELFT>(S, Body, RelOff));
return Expr;
}
+
if (Body.getVisibility() != STV_DEFAULT) {
- error(S.getLocation(RelOff) + ": cannot preempt symbol '" + toString(Body) +
- "' defined in " + toString(Body.File));
+ error("cannot preempt symbol: " + toString(Body) +
+ getLocation<ELFT>(S, Body, RelOff));
return Expr;
}
+
if (Body.isObject()) {
// Produce a copy relocation.
- auto *B = cast<SharedSymbol<ELFT>>(&Body);
- if (!B->needsCopy())
- addCopyRelSymbol(B);
+ auto *B = cast<SharedSymbol>(&Body);
+ if (!B->NeedsCopy) {
+ if (Config->ZNocopyreloc)
+ error("unresolvable relocation " + toString(Type) +
+ " against symbol '" + toString(*B) +
+ "'; recompile with -fPIC or remove '-z nocopyreloc'" +
+ getLocation<ELFT>(S, Body, RelOff));
+
+ addCopyRelSymbol<ELFT>(B);
+ }
return Expr;
}
+
if (Body.isFunc()) {
// This handles a non PIC program call to function in a shared library. In
// an ideal world, we could just report an error saying the relocation can
@@ -516,61 +603,109 @@ static RelExpr adjustExpr(const elf::ObjectFile<ELFT> &File, SymbolBody &Body,
// that points to the real function is a dedicated got entry used by the
// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
// R_386_JMP_SLOT, etc).
- Body.NeedsCopyOrPltAddr = true;
+ Body.NeedsPltAddr = true;
return toPlt(Expr);
}
- error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
- " is missing type");
+ error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) +
+ " has no type");
return Expr;
}
+// Returns an addend of a given relocation. If it is RELA, an addend
+// is in a relocation itself. If it is REL, we need to read it from an
+// input section.
+template <class ELFT, class RelTy>
+static int64_t computeAddend(const RelTy &Rel, const uint8_t *Buf) {
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ int64_t A = RelTy::IsRela
+ ? getAddend<ELFT>(Rel)
+ : Target->getImplicitAddend(Buf + Rel.r_offset, Type);
+
+ if (Config->EMachine == EM_PPC64 && Config->Pic && Type == R_PPC64_TOC)
+ A += getPPC64TocBase();
+ return A;
+}
+
+// MIPS has an odd notion of "paired" relocations to calculate addends.
+// For example, if a relocation is of R_MIPS_HI16, there must be a
+// R_MIPS_LO16 relocation after that, and an addend is calculated using
+// the two relocations.
template <class ELFT, class RelTy>
-static typename ELFT::uint computeAddend(const elf::ObjectFile<ELFT> &File,
- const uint8_t *SectionData,
- const RelTy *End, const RelTy &RI,
- RelExpr Expr, SymbolBody &Body) {
- typedef typename ELFT::uint uintX_t;
-
- uint32_t Type = RI.getType(Config->Mips64EL);
- uintX_t Addend = getAddend<ELFT>(RI);
- const uint8_t *BufLoc = SectionData + RI.r_offset;
- if (!RelTy::IsRela)
- Addend += Target->getImplicitAddend(BufLoc, Type);
- if (Config->EMachine == EM_MIPS) {
- Addend += findMipsPairedAddend<ELFT>(SectionData, BufLoc, Body, &RI, End);
- if (Type == R_MIPS_LO16 && Expr == R_PC)
- // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp
- // symbol. In that case we should use the following formula for
- // calculation "AHL + GP - P + 4". Let's add 4 right here.
- // For details see p. 4-19 at
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Addend += 4;
- if (Expr == R_MIPS_GOTREL && Body.isLocal())
- Addend += File.MipsGp0;
+static int64_t computeMipsAddend(const RelTy &Rel, InputSectionBase &Sec,
+ RelExpr Expr, SymbolBody &Body,
+ const RelTy *End) {
+ if (Expr == R_MIPS_GOTREL && Body.isLocal())
+ return Sec.getFile<ELFT>()->MipsGp0;
+
+ // The ABI says that the paired relocation is used only for REL.
+ // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ if (RelTy::IsRela)
+ return 0;
+
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
+ uint32_t PairTy = getMipsPairType(Type, Body);
+ if (PairTy == R_MIPS_NONE)
+ return 0;
+
+ 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
+ // the relocation table, so we need to do linear search. *sigh*
+ for (const RelTy *RI = &Rel; RI != End; ++RI) {
+ if (RI->getType(Config->IsMips64EL) != PairTy)
+ continue;
+ if (RI->getSymbol(Config->IsMips64EL) != SymIndex)
+ continue;
+
+ endianness E = Config->Endianness;
+ int32_t Hi = (read32(Buf + Rel.r_offset, E) & 0xffff) << 16;
+ int32_t Lo = SignExtend32<16>(read32(Buf + RI->r_offset, E));
+ return Hi + Lo;
}
- if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC)
- Addend += getPPC64TocBase();
- return Addend;
+
+ warn("can't find matching " + toString(PairTy) + " relocation for " +
+ toString(Type));
+ return 0;
}
template <class ELFT>
-static void reportUndefined(SymbolBody &Sym, InputSectionBase<ELFT> &S,
- typename ELFT::uint Offset) {
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
+static void reportUndefined(SymbolBody &Sym, InputSectionBase &S,
+ uint64_t Offset) {
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll)
return;
- if (Config->Shared && Sym.symbol()->Visibility == STV_DEFAULT &&
- Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
+ bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL &&
+ Sym.getVisibility() == STV_DEFAULT;
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal)
return;
std::string Msg =
- S.getLocation(Offset) + ": undefined symbol '" + toString(Sym) + "'";
+ "undefined symbol: " + toString(Sym) + "\n>>> referenced by ";
- if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
+ std::string Src = S.getSrcMsg<ELFT>(Offset);
+ if (!Src.empty())
+ Msg += Src + "\n>>> ";
+ Msg += S.getObjMsg<ELFT>(Offset);
+
+ if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll ||
+ (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) {
warn(Msg);
- else
+ } else {
error(Msg);
+
+ if (Config->ArchiveWithoutSymbolsSeen) {
+ message("At least one archive listed no symbols in its index."
+ " This can happen when creating archives with a version"
+ " of ar that does not understand the object files in"
+ " the archive. For example, if you are using LLVM"
+ " bitcode objects (such as created by -flto), you may"
+ " need to use llvm-ar or GNU ar with a plugin.");
+ // Reset to false so that we print the message only once.
+ Config->ArchiveWithoutSymbolsSeen = false;
+ }
+ }
}
template <class RelTy>
@@ -584,11 +719,95 @@ mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
uint32_t Processed = 0;
for (; I != E && Offset == I->r_offset; ++I) {
++Processed;
- Type |= I->getType(Config->Mips64EL) << (8 * Processed);
+ Type |= I->getType(Config->IsMips64EL) << (8 * Processed);
}
return std::make_pair(Type, Processed);
}
+// .eh_frame sections are mergeable input sections, so their input
+// offsets are not linearly mapped to output section. For each input
+// offset, we need to find a section piece containing the offset and
+// add the piece's base address to the input offset to compute the
+// output offset. That isn't cheap.
+//
+// This class is to speed up the offset computation. When we process
+// relocations, we access offsets in the monotonically increasing
+// order. So we can optimize for that access pattern.
+//
+// For sections other than .eh_frame, this class doesn't do anything.
+namespace {
+class OffsetGetter {
+public:
+ explicit OffsetGetter(InputSectionBase &Sec) {
+ if (auto *Eh = dyn_cast<EhInputSection>(&Sec)) {
+ P = Eh->Pieces;
+ Size = Eh->Pieces.size();
+ }
+ }
+
+ // Translates offsets in input sections to offsets in output sections.
+ // Given offset must increase monotonically. We assume that P is
+ // sorted by InputOff.
+ uint64_t get(uint64_t Off) {
+ if (P.empty())
+ return Off;
+
+ while (I != Size && P[I].InputOff + P[I].size() <= Off)
+ ++I;
+ if (I == Size)
+ return Off;
+
+ // P must be contiguous, so there must be no holes in between.
+ assert(P[I].InputOff <= Off && "Relocation not in any piece");
+
+ // Offset -1 means that the piece is dead (i.e. garbage collected).
+ if (P[I].OutputOff == -1)
+ return -1;
+ return P[I].OutputOff + Off - P[I].InputOff;
+ }
+
+private:
+ ArrayRef<EhSectionPiece> P;
+ size_t I = 0;
+ size_t Size;
+};
+} // namespace
+
+template <class ELFT, class GotPltSection>
+static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt,
+ RelocationSection<ELFT> *Rel, uint32_t Type,
+ SymbolBody &Sym, bool UseSymVA) {
+ Plt->addEntry<ELFT>(Sym);
+ GotPlt->addEntry(Sym);
+ Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0});
+}
+
+template <class ELFT>
+static void addGotEntry(SymbolBody &Sym, bool Preemptible) {
+ In<ELFT>::Got->addEntry(Sym);
+
+ uint64_t Off = Sym.getGotOffset();
+ uint32_t DynType;
+ RelExpr Expr = R_ABS;
+
+ if (Sym.isTls()) {
+ DynType = Target->TlsGotRel;
+ Expr = R_TLS;
+ } else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) {
+ DynType = Target->RelativeRel;
+ } else {
+ DynType = Target->GotRel;
+ }
+
+ bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Sym));
+ if (!Constant)
+ In<ELFT>::RelaDyn->addReloc(
+ {DynType, In<ELFT>::Got, Off, !Preemptible, &Sym, 0});
+
+ if (Constant || (!Config->IsRela && !Preemptible))
+ In<ELFT>::Got->Relocations.push_back({Expr, DynType, Off, 0, &Sym});
+}
+
// The reason we have to do this early scan is as follows
// * To mmap the output file, we need to know the size
// * For that, we need to know how many dynamic relocs we will have.
@@ -603,114 +822,104 @@ mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) {
// complicates things for the dynamic linker and means we would have to reserve
// space for the extra PT_LOAD even if we end up not using it.
template <class ELFT, class RelTy>
-static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
- typedef typename ELFT::uint uintX_t;
-
- bool IsWrite = C.Flags & SHF_WRITE;
-
- auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
- In<ELFT>::RelaDyn->addReloc(Reloc);
- };
-
- const elf::ObjectFile<ELFT> *File = C.getFile();
- ArrayRef<uint8_t> SectionData = C.Data;
- const uint8_t *Buf = SectionData.begin();
+static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) {
+ OffsetGetter GetOffset(Sec);
- ArrayRef<EhSectionPiece> Pieces;
- if (auto *Eh = dyn_cast<EhInputSection<ELFT>>(&C))
- Pieces = Eh->Pieces;
-
- ArrayRef<EhSectionPiece>::iterator PieceI = Pieces.begin();
- ArrayRef<EhSectionPiece>::iterator PieceE = Pieces.end();
-
- for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
- const RelTy &RI = *I;
- SymbolBody &Body = File->getRelocTargetSym(RI);
- uint32_t Type = RI.getType(Config->Mips64EL);
+ for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) {
+ const RelTy &Rel = *I;
+ SymbolBody &Body = Sec.getFile<ELFT>()->getRelocTargetSym(Rel);
+ uint32_t Type = Rel.getType(Config->IsMips64EL);
if (Config->MipsN32Abi) {
uint32_t Processed;
std::tie(Type, Processed) =
- mergeMipsN32RelTypes(Type, RI.r_offset, I + 1, E);
+ mergeMipsN32RelTypes(Type, Rel.r_offset, I + 1, End);
I += Processed;
}
- // We only report undefined symbols if they are referenced somewhere in the
- // code.
+ // Compute the offset of this section in the output section.
+ uint64_t Offset = GetOffset.get(Rel.r_offset);
+ if (Offset == uint64_t(-1))
+ continue;
+
+ // Report undefined symbols. The fact that we report undefined
+ // symbols here means that we report undefined symbols only when
+ // they have relocations pointing to them. We don't care about
+ // undefined symbols that are in dead-stripped sections.
if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak())
- reportUndefined(Body, C, RI.r_offset);
+ reportUndefined<ELFT>(Body, Sec, Rel.r_offset);
+
+ RelExpr Expr =
+ Target->getRelExpr(Type, Body, Sec.Data.begin() + Rel.r_offset);
+
+ // Ignore "hint" relocations because they are only markers for relaxation.
+ if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
+ continue;
- RelExpr Expr = Target->getRelExpr(Type, Body);
bool Preemptible = isPreemptible(Body, Type);
- Expr = adjustExpr(*File, Body, IsWrite, Expr, Type, Buf + RI.r_offset, C,
- RI.r_offset);
+ Expr = adjustExpr<ELFT>(Body, Expr, Type, Sec.Data.data() + Rel.r_offset,
+ Sec, Rel.r_offset);
if (ErrorCount)
continue;
- // Skip a relocation that points to a dead piece
- // in a eh_frame section.
- while (PieceI != PieceE &&
- (PieceI->InputOff + PieceI->size() <= RI.r_offset))
- ++PieceI;
-
- // Compute the offset of this section in the output section. We do it here
- // to try to compute it only once.
- uintX_t Offset;
- if (PieceI != PieceE) {
- assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece");
- if (PieceI->OutputOff == -1)
- continue;
- Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff;
- } else {
- Offset = RI.r_offset;
- }
-
// This relocation does not require got entry, but it is relative to got and
// needs it to be created. Here we request for that.
- if (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END ||
- Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC)
+ if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL,
+ R_GOTREL_FROM_END, R_PPC_TOC>(Expr))
In<ELFT>::Got->HasGotOffRel = true;
- uintX_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body);
+ // Read an addend.
+ int64_t Addend = computeAddend<ELFT>(Rel, Sec.Data.data());
+ if (Config->EMachine == EM_MIPS)
+ Addend += computeMipsAddend<ELFT>(Rel, Sec, Expr, Body, End);
+ // Process some TLS relocations, including relaxing TLS relocations.
+ // Note that this function does not handle all TLS relocations.
if (unsigned Processed =
- handleTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr)) {
+ handleTlsRelocation<ELFT>(Type, Body, Sec, Offset, Addend, Expr)) {
I += (Processed - 1);
continue;
}
- // Ignore "hint" and TLS Descriptor call relocation because they are
- // only markers for relaxation.
- if (isRelExprOneOf<R_HINT, R_TLSDESC_CALL>(Expr))
- continue;
+ // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+ if (needsPlt(Expr) && !Body.isInPlt()) {
+ if (Body.isGnuIFunc() && !Preemptible)
+ addPltEntry(InX::Iplt, In<ELFT>::IgotPlt, In<ELFT>::RelaIplt,
+ Target->IRelativeRel, Body, true);
+ else
+ addPltEntry(InX::Plt, In<ELFT>::GotPlt, In<ELFT>::RelaPlt,
+ Target->PltRel, Body, !Preemptible);
+ }
- if (needsPlt(Expr) ||
- isRelExprOneOf<R_THUNK_ABS, R_THUNK_PC, R_THUNK_PLT_PC>(Expr) ||
- refersToGotEntry(Expr) || !isPreemptible(Body, Type)) {
- // If the relocation points to something in the file, we can process it.
- bool Constant =
- isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, C, RI.r_offset);
-
- // If the output being produced is position independent, the final value
- // is still not known. In that case we still need some help from the
- // dynamic linker. We can however do better than just copying the incoming
- // relocation. We can process some of it and and just ask the dynamic
- // linker to add the load address.
- if (!Constant)
- AddDyn({Target->RelativeRel, &C, Offset, true, &Body, Addend});
-
- // If the produced value is a constant, we just remember to write it
- // when outputting this section. We also have to do it if the format
- // uses Elf_Rel, since in that case the written value is the addend.
- if (Constant || !RelTy::IsRela)
- C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
- } else {
+ // Create a GOT slot if a relocation needs GOT.
+ if (needsGot(Expr)) {
+ if (Config->EMachine == EM_MIPS) {
+ // MIPS ABI has special rules to process GOT entries and doesn't
+ // require relocation entries for them. A special case is TLS
+ // relocations. In that case dynamic loader applies dynamic
+ // relocations to initialize TLS GOT entries.
+ // See "Global Offset Table" in Chapter 5 in the following document
+ // for detailed description:
+ // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+ In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
+ if (Body.isTls() && Body.isPreemptible())
+ In<ELFT>::RelaDyn->addReloc({Target->TlsGotRel, In<ELFT>::MipsGot,
+ Body.getGotOffset(), false, &Body, 0});
+ } else if (!Body.isInGot()) {
+ addGotEntry<ELFT>(Body, Preemptible);
+ }
+ }
+
+ if (!needsPlt(Expr) && !needsGot(Expr) && isPreemptible(Body, Type)) {
// We don't know anything about the finaly symbol. Just ask the dynamic
// linker to handle the relocation for us.
if (!Target->isPicRel(Type))
- error(C.getLocation(Offset) + ": relocation " + toString(Type) +
- " cannot be used against shared object; recompile with -fPIC.");
- AddDyn({Target->getDynRel(Type), &C, Offset, false, &Body, Addend});
+ error("relocation " + toString(Type) +
+ " cannot be used against shared object; recompile with -fPIC" +
+ getLocation<ELFT>(Sec, Body, Offset));
+
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->getDynRel(Type), &Sec, Offset, false, &Body, Addend});
// MIPS ABI turns using of GOT and dynamic relocations inside out.
// While regular ABI uses dynamic relocations to fill up GOT entries
@@ -732,114 +941,163 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
continue;
}
- // At this point we are done with the relocated position. Some relocations
- // also require us to create a got or plt entry.
-
- // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol.
- if (needsPlt(Expr)) {
- if (Body.isInPlt())
- continue;
-
- if (Body.isGnuIFunc() && !Preemptible) {
- In<ELFT>::Iplt->addEntry(Body);
- In<ELFT>::IgotPlt->addEntry(Body);
- In<ELFT>::RelaIplt->addReloc({Target->IRelativeRel, In<ELFT>::IgotPlt,
- Body.getGotPltOffset<ELFT>(),
- !Preemptible, &Body, 0});
- } else {
- In<ELFT>::Plt->addEntry(Body);
- In<ELFT>::GotPlt->addEntry(Body);
- In<ELFT>::RelaPlt->addReloc({Target->PltRel, In<ELFT>::GotPlt,
- Body.getGotPltOffset<ELFT>(), !Preemptible,
- &Body, 0});
- }
- continue;
- }
+ // If the relocation points to something in the file, we can process it.
+ bool IsConstant =
+ isStaticLinkTimeConstant<ELFT>(Expr, Type, Body, Sec, Rel.r_offset);
- if (refersToGotEntry(Expr)) {
- if (Config->EMachine == EM_MIPS) {
- // MIPS ABI has special rules to process GOT entries and doesn't
- // require relocation entries for them. A special case is TLS
- // relocations. In that case dynamic loader applies dynamic
- // relocations to initialize TLS GOT entries.
- // See "Global Offset Table" in Chapter 5 in the following document
- // for detailed description:
- // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- In<ELFT>::MipsGot->addEntry(Body, Addend, Expr);
- if (Body.isTls() && Body.isPreemptible())
- AddDyn({Target->TlsGotRel, In<ELFT>::MipsGot,
- Body.getGotOffset<ELFT>(), false, &Body, 0});
- continue;
- }
+ // If the output being produced is position independent, the final value
+ // is still not known. In that case we still need some help from the
+ // dynamic linker. We can however do better than just copying the incoming
+ // relocation. We can process some of it and and just ask the dynamic
+ // linker to add the load address.
+ if (!IsConstant)
+ In<ELFT>::RelaDyn->addReloc(
+ {Target->RelativeRel, &Sec, Offset, true, &Body, Addend});
- if (Body.isInGot())
- continue;
-
- In<ELFT>::Got->addEntry(Body);
- uintX_t Off = Body.getGotOffset<ELFT>();
- uint32_t DynType;
- RelExpr GotRE = R_ABS;
- if (Body.isTls()) {
- DynType = Target->TlsGotRel;
- GotRE = R_TLS;
- } else if (!Preemptible && Config->Pic && !isAbsolute<ELFT>(Body))
- DynType = Target->RelativeRel;
- else
- DynType = Target->GotRel;
-
- // FIXME: this logic is almost duplicated above.
- bool Constant = !Preemptible && !(Config->Pic && !isAbsolute<ELFT>(Body));
- if (!Constant)
- AddDyn({DynType, In<ELFT>::Got, Off, !Preemptible, &Body, 0});
- if (Constant || (!RelTy::IsRela && !Preemptible))
- In<ELFT>::Got->Relocations.push_back({GotRE, DynType, Off, 0, &Body});
- continue;
- }
+ // If the produced value is a constant, we just remember to write it
+ // when outputting this section. We also have to do it if the format
+ // uses Elf_Rel, since in that case the written value is the addend.
+ if (IsConstant || !RelTy::IsRela)
+ Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
}
}
-template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &S) {
+template <class ELFT> void elf::scanRelocations(InputSectionBase &S) {
if (S.AreRelocsRela)
- scanRelocs(S, S.relas());
+ scanRelocs<ELFT>(S, S.relas<ELFT>());
else
- scanRelocs(S, S.rels());
+ scanRelocs<ELFT>(S, S.rels<ELFT>());
}
-template <class ELFT, class RelTy>
-static void createThunks(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
- const elf::ObjectFile<ELFT> *File = C.getFile();
- for (const RelTy &Rel : Rels) {
- SymbolBody &Body = File->getRelocTargetSym(Rel);
- uint32_t Type = Rel.getType(Config->Mips64EL);
- RelExpr Expr = Target->getRelExpr(Type, Body);
- if (!isPreemptible(Body, Type) && needsPlt(Expr))
- Expr = fromPlt(Expr);
- Expr = Target->getThunkExpr(Expr, Type, *File, Body);
- // Some targets might require creation of thunks for relocations.
- // Now we support only MIPS which requires LA25 thunk to call PIC
- // code from non-PIC one, and ARM which requires interworking.
- if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) {
- auto *Sec = cast<InputSection<ELFT>>(&C);
- addThunk<ELFT>(Type, Body, *Sec);
+// Insert the Thunks for OutputSection OS into their designated place
+// in the Sections vector, and recalculate the InputSection output section
+// offsets.
+// This may invalidate any output section offsets stored outside of InputSection
+template <class ELFT>
+void ThunkCreator<ELFT>::mergeThunks(OutputSection *OS,
+ std::vector<ThunkSection *> &Thunks) {
+ // Order Thunks in ascending OutSecOff
+ auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) {
+ return A->OutSecOff < B->OutSecOff;
+ };
+ std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp);
+
+ // Merge sorted vectors of Thunks and InputSections by OutSecOff
+ std::vector<InputSection *> Tmp;
+ Tmp.reserve(OS->Sections.size() + Thunks.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)
+ // Check if Thunk is immediately before any specific Target InputSection
+ // for example Mips LA25 Thunks.
+ if (auto *TA = dyn_cast<ThunkSection>(A))
+ if (TA && TA->getTargetInputSection() == B)
+ return true;
+ return false;
+ };
+ std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(),
+ Thunks.end(), std::back_inserter(Tmp), MergeCmp);
+ OS->Sections = std::move(Tmp);
+ OS->assignOffsets();
+}
+
+template <class ELFT>
+ThunkSection *ThunkCreator<ELFT>::getOSThunkSec(ThunkSection *&TS,
+ OutputSection *OS) {
+ if (TS == nullptr) {
+ uint32_t Off = 0;
+ for (auto *IS : OS->Sections) {
+ Off = IS->OutSecOff + IS->getSize();
+ if ((IS->Flags & SHF_EXECINSTR) == 0)
+ break;
}
+ TS = make<ThunkSection>(OS, Off);
+ ThunkSections[OS].push_back(TS);
}
+ return TS;
}
-template <class ELFT> void createThunks(InputSectionBase<ELFT> &S) {
- if (S.AreRelocsRela)
- createThunks(S, S.relas());
- else
- createThunks(S, S.rels());
+template <class ELFT>
+ThunkSection *ThunkCreator<ELFT>::getISThunkSec(InputSection *IS,
+ OutputSection *OS) {
+ ThunkSection *TS = ThunkedSections.lookup(IS);
+ if (TS)
+ return TS;
+ auto *TOS = cast<OutputSection>(IS->OutSec);
+ TS = make<ThunkSection>(TOS, IS->OutSecOff);
+ ThunkSections[TOS].push_back(TS);
+ ThunkedSections[IS] = TS;
+ return TS;
}
-template void scanRelocations<ELF32LE>(InputSectionBase<ELF32LE> &);
-template void scanRelocations<ELF32BE>(InputSectionBase<ELF32BE> &);
-template void scanRelocations<ELF64LE>(InputSectionBase<ELF64LE> &);
-template void scanRelocations<ELF64BE>(InputSectionBase<ELF64BE> &);
-
-template void createThunks<ELF32LE>(InputSectionBase<ELF32LE> &);
-template void createThunks<ELF32BE>(InputSectionBase<ELF32BE> &);
-template void createThunks<ELF64LE>(InputSectionBase<ELF64LE> &);
-template void createThunks<ELF64BE>(InputSectionBase<ELF64BE> &);
+template <class ELFT>
+std::pair<Thunk *, bool> ThunkCreator<ELFT>::getThunk(SymbolBody &Body,
+ uint32_t Type) {
+ auto res = ThunkedSymbols.insert({&Body, nullptr});
+ if (res.second)
+ res.first->second = addThunk<ELFT>(Type, Body);
+ return std::make_pair(res.first->second, res.second);
}
+
+// Process all relocations from the InputSections that have been assigned
+// to OutputSections and redirect through Thunks if needed.
+//
+// createThunks must be called after scanRelocs has created the Relocations for
+// each InputSection. It must be called before the static symbol table is
+// finalized. If any Thunks are added to an OutputSection the output section
+// offsets of the InputSections will change.
+//
+// FIXME: All Thunks are assumed to be in range of the relocation. Range
+// extension Thunks are not yet supported.
+template <class ELFT>
+bool ThunkCreator<ELFT>::createThunks(
+ ArrayRef<OutputSection *> OutputSections) {
+ // Create all the Thunks and insert them into synthetic ThunkSections. The
+ // ThunkSections are later inserted back into the OutputSection.
+
+ // We separate the creation of ThunkSections from the insertion of the
+ // ThunkSections back into the OutputSection as ThunkSections are not always
+ // inserted into the same OutputSection as the caller.
+ for (OutputSection *OS : OutputSections) {
+ ThunkSection *OSTS = nullptr;
+ for (InputSection *IS : OS->Sections) {
+ for (Relocation &Rel : IS->Relocations) {
+ SymbolBody &Body = *Rel.Sym;
+ if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body))
+ continue;
+ Thunk *T;
+ bool IsNew;
+ std::tie(T, IsNew) = getThunk(Body, Rel.Type);
+ if (IsNew) {
+ // Find or create a ThunkSection for the new Thunk
+ ThunkSection *TS;
+ if (auto *TIS = T->getTargetInputSection())
+ TS = getISThunkSec(TIS, OS);
+ else
+ TS = getOSThunkSec(OSTS, OS);
+ TS->addThunk(T);
+ }
+ // Redirect relocation to Thunk, we never go via the PLT to a Thunk
+ Rel.Sym = T->ThunkSym;
+ Rel.Expr = fromPlt(Rel.Expr);
+ }
+ }
+ }
+
+ // Merge all created synthetic ThunkSections back into OutputSection
+ for (auto &KV : ThunkSections)
+ mergeThunks(KV.first, KV.second);
+ return !ThunkSections.empty();
}
+
+template void elf::scanRelocations<ELF32LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF32BE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64LE>(InputSectionBase &);
+template void elf::scanRelocations<ELF64BE>(InputSectionBase &);
+
+template class elf::ThunkCreator<ELF32LE>;
+template class elf::ThunkCreator<ELF32BE>;
+template class elf::ThunkCreator<ELF64LE>;
+template class elf::ThunkCreator<ELF64BE>;
diff --git a/ELF/Relocations.h b/ELF/Relocations.h
index b5825bdd5e59..f8f0f11e14a9 100644
--- a/ELF/Relocations.h
+++ b/ELF/Relocations.h
@@ -11,13 +11,16 @@
#define LLD_ELF_RELOCATIONS_H
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include <map>
+#include <vector>
namespace lld {
namespace elf {
class SymbolBody;
-class InputSectionData;
-template <class ELFT> class InputSection;
-template <class ELFT> class InputSectionBase;
+class InputSection;
+class InputSectionBase;
+class OutputSection;
// List of target-independent relocation types. Relocations read
// from files are converted to these types so that the main code
@@ -34,39 +37,39 @@ enum RelExpr {
R_GOT_PAGE_PC,
R_GOT_PC,
R_HINT,
+ R_MIPS_GOTREL,
+ R_MIPS_GOT_GP,
+ R_MIPS_GOT_GP_PC,
R_MIPS_GOT_LOCAL_PAGE,
R_MIPS_GOT_OFF,
R_MIPS_GOT_OFF32,
- R_MIPS_GOTREL,
R_MIPS_TLSGD,
R_MIPS_TLSLD,
R_NEG_TLS,
+ R_NONE,
R_PAGE_PC,
R_PC,
R_PLT,
- R_PLT_PC,
R_PLT_PAGE_PC,
+ R_PLT_PC,
R_PPC_OPD,
R_PPC_PLT_OPD,
R_PPC_TOC,
R_RELAX_GOT_PC,
R_RELAX_GOT_PC_NOPIC,
R_RELAX_TLS_GD_TO_IE,
- R_RELAX_TLS_GD_TO_IE_END,
R_RELAX_TLS_GD_TO_IE_ABS,
+ R_RELAX_TLS_GD_TO_IE_END,
R_RELAX_TLS_GD_TO_IE_PAGE_PC,
R_RELAX_TLS_GD_TO_LE,
R_RELAX_TLS_GD_TO_LE_NEG,
R_RELAX_TLS_IE_TO_LE,
R_RELAX_TLS_LD_TO_LE,
R_SIZE,
- R_THUNK_ABS,
- R_THUNK_PC,
- R_THUNK_PLT_PC,
R_TLS,
R_TLSDESC,
- R_TLSDESC_PAGE,
R_TLSDESC_CALL,
+ R_TLSDESC_PAGE,
R_TLSGD,
R_TLSGD_PC,
R_TLSLD,
@@ -107,21 +110,44 @@ struct Relocation {
RelExpr Expr;
uint32_t Type;
uint64_t Offset;
- uint64_t Addend;
+ int64_t Addend;
SymbolBody *Sym;
};
-template <class ELFT> void scanRelocations(InputSectionBase<ELFT> &);
+template <class ELFT> void scanRelocations(InputSectionBase &);
-template <class ELFT> void createThunks(InputSectionBase<ELFT> &);
+class ThunkSection;
+class Thunk;
+template <class ELFT> class ThunkCreator {
+public:
+ // Return true if Thunks have been added to OutputSections
+ bool createThunks(ArrayRef<OutputSection *> OutputSections);
+
+private:
+ void mergeThunks(OutputSection *OS, std::vector<ThunkSection *> &Thunks);
+ ThunkSection *getOSThunkSec(ThunkSection *&TS, OutputSection *OS);
+ ThunkSection *getISThunkSec(InputSection *IS, OutputSection *OS);
+ std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type);
+
+ // Track Symbols that already have a Thunk
+ llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols;
+
+ // Track InputSections that have a ThunkSection placed in front
+ llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections;
+
+ // Track the ThunksSections that need to be inserted into an OutputSection
+ std::map<OutputSection *, std::vector<ThunkSection *>> ThunkSections;
+};
+
+// Return a int64_t to make sure we get the sign extension out of the way as
+// early as possible.
template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rel &Rel) {
+static inline int64_t getAddend(const typename ELFT::Rel &Rel) {
return 0;
}
-
template <class ELFT>
-static inline typename ELFT::uint getAddend(const typename ELFT::Rela &Rel) {
+static inline int64_t getAddend(const typename ELFT::Rela &Rel) {
return Rel.r_addend;
}
}
diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp
new file mode 100644
index 000000000000..86720de3527c
--- /dev/null
+++ b/ELF/ScriptLexer.cpp
@@ -0,0 +1,285 @@
+//===- ScriptLexer.cpp ----------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a lexer for the linker script.
+//
+// The linker script's grammar is not complex but ambiguous due to the
+// lack of the formal specification of the language. What we are trying to
+// do in this and other files in LLD is to make a "reasonable" linker
+// script processor.
+//
+// Among simplicity, compatibility and efficiency, we put the most
+// emphasis on simplicity when we wrote this lexer. Compatibility with the
+// GNU linkers is important, but we did not try to clone every tiny corner
+// case of their lexers, as even ld.bfd and ld.gold are subtly different
+// in various corner cases. We do not care much about efficiency because
+// the time spent in parsing linker scripts is usually negligible.
+//
+// Our grammar of the linker script is LL(2), meaning that it needs at
+// most two-token lookahead to parse. The only place we need two-token
+// lookahead is labels in version scripts, where we need to parse "local :"
+// as if "local:".
+//
+// Overall, this lexer works fine for most linker scripts. There might
+// be room for improving compatibility, but that's probably not at the
+// top of our todo list.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ScriptLexer.h"
+#include "Error.h"
+#include "llvm/ADT/Twine.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf;
+
+// Returns a whole line containing the current token.
+StringRef ScriptLexer::getLine() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+
+ size_t Pos = S.rfind('\n', Tok.data() - S.data());
+ if (Pos != StringRef::npos)
+ S = S.substr(Pos + 1);
+ return S.substr(0, S.find_first_of("\r\n"));
+}
+
+// Returns 1-based line number of the current token.
+size_t ScriptLexer::getLineNumber() {
+ StringRef S = getCurrentMB().getBuffer();
+ StringRef Tok = Tokens[Pos - 1];
+ return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+}
+
+// Returns 0-based column number of the current token.
+size_t ScriptLexer::getColumnNumber() {
+ StringRef Tok = Tokens[Pos - 1];
+ return Tok.data() - getLine().data();
+}
+
+std::string ScriptLexer::getCurrentLocation() {
+ std::string Filename = getCurrentMB().getBufferIdentifier();
+ if (!Pos)
+ return Filename;
+ return (Filename + ":" + Twine(getLineNumber())).str();
+}
+
+ScriptLexer::ScriptLexer(MemoryBufferRef MB) { tokenize(MB); }
+
+// We don't want to record cascading errors. Keep only the first one.
+void ScriptLexer::setError(const Twine &Msg) {
+ if (Error)
+ return;
+ Error = true;
+
+ if (!Pos) {
+ error(getCurrentLocation() + ": " + Msg);
+ return;
+ }
+
+ std::string S = getCurrentLocation() + ": ";
+ error(S + Msg);
+ error(S + getLine());
+ error(S + std::string(getColumnNumber(), ' ') + "^");
+}
+
+// Split S into linker script tokens.
+void ScriptLexer::tokenize(MemoryBufferRef MB) {
+ std::vector<StringRef> Vec;
+ MBs.push_back(MB);
+ StringRef S = MB.getBuffer();
+ StringRef Begin = S;
+
+ for (;;) {
+ S = skipSpace(S);
+ if (S.empty())
+ break;
+
+ // Quoted token. Note that double-quote characters are parts of a token
+ // because, in a glob match context, only unquoted tokens are interpreted
+ // as glob patterns. Double-quoted tokens are literal patterns in that
+ // context.
+ if (S.startswith("\"")) {
+ size_t E = S.find("\"", 1);
+ if (E == StringRef::npos) {
+ StringRef Filename = MB.getBufferIdentifier();
+ size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
+ error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
+ return;
+ }
+
+ Vec.push_back(S.take_front(E + 1));
+ S = S.substr(E + 1);
+ continue;
+ }
+
+ // Unquoted token. This is more relaxed than tokens in C-like language,
+ // so that you can write "file-name.cpp" as one bare token, for example.
+ size_t Pos = S.find_first_not_of(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789_.$/\\~=+[]*?-!<>^:");
+
+ // A character that cannot start a word (which is usually a
+ // punctuation) forms a single character token.
+ if (Pos == 0)
+ Pos = 1;
+ Vec.push_back(S.substr(0, Pos));
+ S = S.substr(Pos);
+ }
+
+ Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+}
+
+// Skip leading whitespace characters or comments.
+StringRef ScriptLexer::skipSpace(StringRef S) {
+ for (;;) {
+ if (S.startswith("/*")) {
+ size_t E = S.find("*/", 2);
+ if (E == StringRef::npos) {
+ error("unclosed comment in a linker script");
+ return "";
+ }
+ S = S.substr(E + 2);
+ continue;
+ }
+ if (S.startswith("#")) {
+ size_t E = S.find('\n', 1);
+ if (E == StringRef::npos)
+ E = S.size() - 1;
+ S = S.substr(E + 1);
+ continue;
+ }
+ size_t Size = S.size();
+ S = S.ltrim();
+ if (S.size() == Size)
+ return S;
+ }
+}
+
+// An erroneous token is handled as if it were the last token before EOF.
+bool ScriptLexer::atEOF() { return Error || Tokens.size() == Pos; }
+
+// Split a given string as an expression.
+// This function returns "3", "*" and "5" for "3*5" for example.
+static std::vector<StringRef> tokenizeExpr(StringRef S) {
+ StringRef Ops = "+-*/:"; // List of operators
+
+ // Quoted strings are literal strings, so we don't want to split it.
+ if (S.startswith("\""))
+ return {S};
+
+ // Split S with +-*/ as separators.
+ std::vector<StringRef> Ret;
+ while (!S.empty()) {
+ size_t E = S.find_first_of(Ops);
+
+ // No need to split if there is no operator.
+ if (E == StringRef::npos) {
+ Ret.push_back(S);
+ break;
+ }
+
+ // Get a token before the opreator.
+ if (E != 0)
+ Ret.push_back(S.substr(0, E));
+
+ // Get the operator as a token.
+ Ret.push_back(S.substr(E, 1));
+ S = S.substr(E + 1);
+ }
+ return Ret;
+}
+
+// In contexts where expressions are expected, the lexer should apply
+// different tokenization rules than the default one. By default,
+// arithmetic operator characters are regular characters, but in the
+// expression context, they should be independent tokens.
+//
+// For example, "foo*3" should be tokenized to "foo", "*" and "3" only
+// in the expression context.
+//
+// This function may split the current token into multiple tokens.
+void ScriptLexer::maybeSplitExpr() {
+ if (!InExpr || Error || atEOF())
+ return;
+
+ std::vector<StringRef> V = tokenizeExpr(Tokens[Pos]);
+ if (V.size() == 1)
+ return;
+ Tokens.erase(Tokens.begin() + Pos);
+ Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
+}
+
+StringRef ScriptLexer::next() {
+ maybeSplitExpr();
+
+ if (Error)
+ return "";
+ if (atEOF()) {
+ setError("unexpected EOF");
+ return "";
+ }
+ return Tokens[Pos++];
+}
+
+StringRef ScriptLexer::peek() {
+ StringRef Tok = next();
+ if (Error)
+ return "";
+ Pos = Pos - 1;
+ return Tok;
+}
+
+bool ScriptLexer::consume(StringRef Tok) {
+ if (peek() == Tok) {
+ skip();
+ return true;
+ }
+ return false;
+}
+
+// Consumes Tok followed by ":". Space is allowed between Tok and ":".
+bool ScriptLexer::consumeLabel(StringRef Tok) {
+ if (consume((Tok + ":").str()))
+ return true;
+ if (Tokens.size() >= Pos + 2 && Tokens[Pos] == Tok &&
+ Tokens[Pos + 1] == ":") {
+ Pos += 2;
+ return true;
+ }
+ return false;
+}
+
+void ScriptLexer::skip() { (void)next(); }
+
+void ScriptLexer::expect(StringRef Expect) {
+ if (Error)
+ return;
+ StringRef Tok = next();
+ if (Tok != Expect)
+ setError(Expect + " expected, but got " + Tok);
+}
+
+// Returns true if S encloses T.
+static bool encloses(StringRef S, StringRef T) {
+ return S.bytes_begin() <= T.bytes_begin() && T.bytes_end() <= S.bytes_end();
+}
+
+MemoryBufferRef ScriptLexer::getCurrentMB() {
+ // Find input buffer containing the current token.
+ assert(!MBs.empty());
+ if (!Pos)
+ return MBs[0];
+
+ for (MemoryBufferRef MB : MBs)
+ if (encloses(MB.getBuffer(), Tokens[Pos - 1]))
+ return MB;
+ llvm_unreachable("getCurrentMB: failed to find a token");
+}
diff --git a/ELF/ScriptLexer.h b/ELF/ScriptLexer.h
new file mode 100644
index 000000000000..64d6d9204864
--- /dev/null
+++ b/ELF/ScriptLexer.h
@@ -0,0 +1,56 @@
+//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_LEXER_H
+#define LLD_ELF_SCRIPT_LEXER_H
+
+#include "lld/Core/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <utility>
+#include <vector>
+
+namespace lld {
+namespace elf {
+
+class ScriptLexer {
+public:
+ explicit ScriptLexer(MemoryBufferRef MB);
+
+ void setError(const Twine &Msg);
+ void tokenize(MemoryBufferRef MB);
+ static StringRef skipSpace(StringRef S);
+ bool atEOF();
+ StringRef next();
+ StringRef peek();
+ void skip();
+ bool consume(StringRef Tok);
+ void expect(StringRef Expect);
+ bool consumeLabel(StringRef Tok);
+ std::string getCurrentLocation();
+
+ std::vector<MemoryBufferRef> MBs;
+ std::vector<StringRef> Tokens;
+ bool InExpr = false;
+ size_t Pos = 0;
+ bool Error = false;
+
+private:
+ void maybeSplitExpr();
+ StringRef getLine();
+ size_t getLineNumber();
+ size_t getColumnNumber();
+
+ MemoryBufferRef getCurrentMB();
+};
+
+} // namespace elf
+} // namespace lld
+
+#endif
diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp
index c740685a15a1..032ecd50f3e3 100644
--- a/ELF/ScriptParser.cpp
+++ b/ELF/ScriptParser.cpp
@@ -7,194 +7,1171 @@
//
//===----------------------------------------------------------------------===//
//
-// This file contains the base parser class for linker script and dynamic
-// list.
+// This file contains a recursive-descendent parser for linker scripts.
+// Parsed results are stored to Config and Script global objects.
//
//===----------------------------------------------------------------------===//
#include "ScriptParser.h"
-#include "Error.h"
-#include "llvm/ADT/Twine.h"
+#include "Config.h"
+#include "Driver.h"
+#include "InputSection.h"
+#include "LinkerScript.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "ScriptLexer.h"
+#include "Symbols.h"
+#include "Target.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include <cassert>
+#include <limits>
+#include <vector>
using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::support::endian;
using namespace lld;
using namespace lld::elf;
-// Returns a whole line containing the current token.
-StringRef ScriptParserBase::getLine() {
- StringRef S = getCurrentMB().getBuffer();
- StringRef Tok = Tokens[Pos - 1];
+static bool isUnderSysroot(StringRef Path);
- size_t Pos = S.rfind('\n', Tok.data() - S.data());
- if (Pos != StringRef::npos)
- S = S.substr(Pos + 1);
- return S.substr(0, S.find_first_of("\r\n"));
+namespace {
+class ScriptParser final : ScriptLexer {
+public:
+ ScriptParser(MemoryBufferRef MB)
+ : ScriptLexer(MB),
+ IsUnderSysroot(isUnderSysroot(MB.getBufferIdentifier())) {}
+
+ void readLinkerScript();
+ void readVersionScript();
+ void readDynamicList();
+
+private:
+ void addFile(StringRef Path);
+
+ void readAsNeeded();
+ void readEntry();
+ void readExtern();
+ void readGroup();
+ void readInclude();
+ void readMemory();
+ void readOutput();
+ void readOutputArch();
+ void readOutputFormat();
+ void readPhdrs();
+ void readSearchDir();
+ void readSections();
+ void readVersion();
+ void readVersionScriptCommand();
+
+ SymbolAssignment *readAssignment(StringRef Name);
+ BytesDataCommand *readBytesDataCommand(StringRef Tok);
+ uint32_t readFill();
+ uint32_t parseFill(StringRef Tok);
+ OutputSectionCommand *readOutputSectionDescription(StringRef OutSec);
+ std::vector<StringRef> readOutputSectionPhdrs();
+ InputSectionDescription *readInputSectionDescription(StringRef Tok);
+ StringMatcher readFilePatterns();
+ std::vector<SectionPattern> readInputSectionsList();
+ InputSectionDescription *readInputSectionRules(StringRef FilePattern);
+ unsigned readPhdrType();
+ SortSectionPolicy readSortKind();
+ SymbolAssignment *readProvideHidden(bool Provide, bool Hidden);
+ SymbolAssignment *readProvideOrAssignment(StringRef Tok);
+ void readSort();
+ AssertCommand *readAssert();
+ Expr readAssertExpr();
+
+ uint64_t readMemoryAssignment(StringRef, StringRef, StringRef);
+ std::pair<uint32_t, uint32_t> readMemoryAttributes();
+
+ Expr readExpr();
+ Expr readExpr1(Expr Lhs, int MinPrec);
+ StringRef readParenLiteral();
+ Expr readPrimary();
+ Expr readTernary(Expr Cond);
+ Expr readParenExpr();
+
+ // For parsing version script.
+ std::vector<SymbolVersion> readVersionExtern();
+ void readAnonymousDeclaration();
+ void readVersionDeclaration(StringRef VerStr);
+
+ std::pair<std::vector<SymbolVersion>, std::vector<SymbolVersion>>
+ readSymbols();
+
+ bool IsUnderSysroot;
+};
+} // namespace
+
+static bool isUnderSysroot(StringRef Path) {
+ if (Config->Sysroot == "")
+ return false;
+ for (; !Path.empty(); Path = sys::path::parent_path(Path))
+ if (sys::fs::equivalent(Config->Sysroot, Path))
+ return true;
+ return false;
}
-// Returns 1-based line number of the current token.
-size_t ScriptParserBase::getLineNumber() {
- StringRef S = getCurrentMB().getBuffer();
- StringRef Tok = Tokens[Pos - 1];
- return S.substr(0, Tok.data() - S.data()).count('\n') + 1;
+// Some operations only support one non absolute value. Move the
+// absolute one to the right hand side for convenience.
+static void moveAbsRight(ExprValue &A, ExprValue &B) {
+ if (A.isAbsolute())
+ std::swap(A, B);
+ if (!B.isAbsolute())
+ error("At least one side of the expression must be absolute");
}
-// Returns 0-based column number of the current token.
-size_t ScriptParserBase::getColumnNumber() {
- StringRef Tok = Tokens[Pos - 1];
- return Tok.data() - getLine().data();
+static ExprValue add(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute, A.Val + B.getValue()};
}
-std::string ScriptParserBase::getCurrentLocation() {
- std::string Filename = getCurrentMB().getBufferIdentifier();
- if (!Pos)
- return Filename;
- return (Filename + ":" + Twine(getLineNumber())).str();
+static ExprValue sub(ExprValue A, ExprValue B) {
+ return {A.Sec, A.Val - B.getValue()};
}
-ScriptParserBase::ScriptParserBase(MemoryBufferRef MB) { tokenize(MB); }
+static ExprValue mul(ExprValue A, ExprValue B) {
+ return A.getValue() * B.getValue();
+}
-// We don't want to record cascading errors. Keep only the first one.
-void ScriptParserBase::setError(const Twine &Msg) {
- if (Error)
+static ExprValue div(ExprValue A, ExprValue B) {
+ if (uint64_t BV = B.getValue())
+ return A.getValue() / BV;
+ error("division by zero");
+ return 0;
+}
+
+static ExprValue bitAnd(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() & B.getValue()) - A.getSecAddr()};
+}
+
+static ExprValue bitOr(ExprValue A, ExprValue B) {
+ moveAbsRight(A, B);
+ return {A.Sec, A.ForceAbsolute,
+ (A.getValue() | B.getValue()) - A.getSecAddr()};
+}
+
+void ScriptParser::readDynamicList() {
+ expect("{");
+ readAnonymousDeclaration();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScript() {
+ readVersionScriptCommand();
+ if (!atEOF())
+ setError("EOF expected, but got " + next());
+}
+
+void ScriptParser::readVersionScriptCommand() {
+ if (consume("{")) {
+ readAnonymousDeclaration();
return;
- Error = true;
+ }
+
+ while (!atEOF() && !Error && peek() != "}") {
+ StringRef VerStr = next();
+ if (VerStr == "{") {
+ setError("anonymous version definition is used in "
+ "combination with other version definitions");
+ return;
+ }
+ expect("{");
+ readVersionDeclaration(VerStr);
+ }
+}
+
+void ScriptParser::readVersion() {
+ expect("{");
+ readVersionScriptCommand();
+ expect("}");
+}
- if (!Pos) {
- error(getCurrentLocation() + ": " + Msg);
+void ScriptParser::readLinkerScript() {
+ while (!atEOF()) {
+ StringRef Tok = next();
+ if (Tok == ";")
+ continue;
+
+ if (Tok == "ASSERT") {
+ Script->Opt.Commands.push_back(readAssert());
+ } else if (Tok == "ENTRY") {
+ readEntry();
+ } else if (Tok == "EXTERN") {
+ readExtern();
+ } else if (Tok == "GROUP" || Tok == "INPUT") {
+ readGroup();
+ } else if (Tok == "INCLUDE") {
+ readInclude();
+ } else if (Tok == "MEMORY") {
+ readMemory();
+ } else if (Tok == "OUTPUT") {
+ readOutput();
+ } else if (Tok == "OUTPUT_ARCH") {
+ readOutputArch();
+ } else if (Tok == "OUTPUT_FORMAT") {
+ readOutputFormat();
+ } else if (Tok == "PHDRS") {
+ readPhdrs();
+ } else if (Tok == "SEARCH_DIR") {
+ readSearchDir();
+ } else if (Tok == "SECTIONS") {
+ readSections();
+ } else if (Tok == "VERSION") {
+ readVersion();
+ } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) {
+ Script->Opt.Commands.push_back(Cmd);
+ } else {
+ setError("unknown directive: " + Tok);
+ }
+ }
+}
+
+void ScriptParser::addFile(StringRef S) {
+ if (IsUnderSysroot && S.startswith("/")) {
+ SmallString<128> PathData;
+ StringRef Path = (Config->Sysroot + S).toStringRef(PathData);
+ if (sys::fs::exists(Path)) {
+ Driver->addFile(Saver.save(Path), /*WithLOption=*/false);
+ return;
+ }
+ }
+
+ if (sys::path::is_absolute(S)) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else if (S.startswith("=")) {
+ if (Config->Sysroot.empty())
+ Driver->addFile(S.substr(1), /*WithLOption=*/false);
+ else
+ Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)),
+ /*WithLOption=*/false);
+ } else if (S.startswith("-l")) {
+ Driver->addLibrary(S.substr(2));
+ } else if (sys::fs::exists(S)) {
+ Driver->addFile(S, /*WithLOption=*/false);
+ } else {
+ if (Optional<std::string> Path = findFromSearchPaths(S))
+ Driver->addFile(Saver.save(*Path), /*WithLOption=*/true);
+ else
+ setError("unable to find " + S);
+ }
+}
+
+void ScriptParser::readAsNeeded() {
+ expect("(");
+ bool Orig = Config->AsNeeded;
+ Config->AsNeeded = true;
+ while (!Error && !consume(")"))
+ addFile(unquote(next()));
+ Config->AsNeeded = Orig;
+}
+
+void ScriptParser::readEntry() {
+ // -e <symbol> takes predecence over ENTRY(<symbol>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->Entry.empty())
+ Config->Entry = Tok;
+ expect(")");
+}
+
+void ScriptParser::readExtern() {
+ expect("(");
+ while (!Error && !consume(")"))
+ Config->Undefined.push_back(next());
+}
+
+void ScriptParser::readGroup() {
+ expect("(");
+ while (!Error && !consume(")")) {
+ if (consume("AS_NEEDED"))
+ readAsNeeded();
+ else
+ addFile(unquote(next()));
+ }
+}
+
+void ScriptParser::readInclude() {
+ StringRef Tok = unquote(next());
+
+ // https://sourceware.org/binutils/docs/ld/File-Commands.html:
+ // The file will be searched for in the current directory, and in any
+ // directory specified with the -L option.
+ if (sys::fs::exists(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(Tok))
+ tokenize(*MB);
+ return;
+ }
+ if (Optional<std::string> Path = findFromSearchPaths(Tok)) {
+ if (Optional<MemoryBufferRef> MB = readFile(*Path))
+ tokenize(*MB);
return;
}
+ setError("cannot open " + Tok);
+}
+
+void ScriptParser::readOutput() {
+ // -o <file> takes predecence over OUTPUT(<file>).
+ expect("(");
+ StringRef Tok = next();
+ if (Config->OutputFile.empty())
+ Config->OutputFile = unquote(Tok);
+ expect(")");
+}
- std::string S = getCurrentLocation() + ": ";
- error(S + Msg);
- error(S + getLine());
- error(S + std::string(getColumnNumber(), ' ') + "^");
+void ScriptParser::readOutputArch() {
+ // OUTPUT_ARCH is ignored for now.
+ expect("(");
+ while (!Error && !consume(")"))
+ skip();
}
-// Split S into linker script tokens.
-void ScriptParserBase::tokenize(MemoryBufferRef MB) {
- std::vector<StringRef> Vec;
- MBs.push_back(MB);
- StringRef S = MB.getBuffer();
- StringRef Begin = S;
+void ScriptParser::readOutputFormat() {
+ // Error checking only for now.
+ expect("(");
+ skip();
+ if (consume(")"))
+ return;
+ expect(",");
+ skip();
+ expect(",");
+ skip();
+ expect(")");
+}
- for (;;) {
- S = skipSpace(S);
- if (S.empty())
- break;
+void ScriptParser::readPhdrs() {
+ expect("{");
+ while (!Error && !consume("}")) {
+ Script->Opt.PhdrsCommands.push_back(
+ {next(), PT_NULL, false, false, UINT_MAX, nullptr});
- // Quoted token. Note that double-quote characters are parts of a token
- // because, in a glob match context, only unquoted tokens are interpreted
- // as glob patterns. Double-quoted tokens are literal patterns in that
- // context.
- if (S.startswith("\"")) {
- size_t E = S.find("\"", 1);
- if (E == StringRef::npos) {
- StringRef Filename = MB.getBufferIdentifier();
- size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n');
- error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote");
- return;
- }
+ PhdrsCommand &PhdrCmd = Script->Opt.PhdrsCommands.back();
+ PhdrCmd.Type = readPhdrType();
- Vec.push_back(S.take_front(E + 1));
- S = S.substr(E + 1);
- continue;
+ while (!Error && !consume(";")) {
+ if (consume("FILEHDR"))
+ PhdrCmd.HasFilehdr = true;
+ else if (consume("PHDRS"))
+ PhdrCmd.HasPhdrs = true;
+ else if (consume("AT"))
+ PhdrCmd.LMAExpr = readParenExpr();
+ else if (consume("FLAGS"))
+ PhdrCmd.Flags = readParenExpr()().getValue();
+ else
+ setError("unexpected header attribute: " + next());
}
+ }
+}
- // Unquoted token. This is more relaxed than tokens in C-like language,
- // so that you can write "file-name.cpp" as one bare token, for example.
- size_t Pos = S.find_first_not_of(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
- "0123456789_.$/\\~=+[]*?-:!<>^");
+void ScriptParser::readSearchDir() {
+ expect("(");
+ StringRef Tok = next();
+ if (!Config->Nostdlib)
+ Config->SearchPaths.push_back(unquote(Tok));
+ expect(")");
+}
+
+void ScriptParser::readSections() {
+ Script->Opt.HasSections = true;
+
+ // -no-rosegment is used to avoid placing read only non-executable sections in
+ // their own segment. We do the same if SECTIONS command is present in linker
+ // script. See comment for computeFlags().
+ Config->SingleRoRx = true;
- // A character that cannot start a word (which is usually a
- // punctuation) forms a single character token.
- if (Pos == 0)
- Pos = 1;
- Vec.push_back(S.substr(0, Pos));
- S = S.substr(Pos);
+ expect("{");
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ BaseCommand *Cmd = readProvideOrAssignment(Tok);
+ if (!Cmd) {
+ if (Tok == "ASSERT")
+ Cmd = readAssert();
+ else
+ Cmd = readOutputSectionDescription(Tok);
+ }
+ Script->Opt.Commands.push_back(Cmd);
}
+}
- Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end());
+static int precedence(StringRef Op) {
+ return StringSwitch<int>(Op)
+ .Cases("*", "/", 5)
+ .Cases("+", "-", 4)
+ .Cases("<<", ">>", 3)
+ .Cases("<", "<=", ">", ">=", "==", "!=", 2)
+ .Cases("&", "|", 1)
+ .Default(-1);
}
-// Skip leading whitespace characters or comments.
-StringRef ScriptParserBase::skipSpace(StringRef S) {
- for (;;) {
- if (S.startswith("/*")) {
- size_t E = S.find("*/", 2);
- if (E == StringRef::npos) {
- error("unclosed comment in a linker script");
- return "";
+StringMatcher ScriptParser::readFilePatterns() {
+ std::vector<StringRef> V;
+ while (!Error && !consume(")"))
+ V.push_back(next());
+ return StringMatcher(V);
+}
+
+SortSectionPolicy ScriptParser::readSortKind() {
+ if (consume("SORT") || consume("SORT_BY_NAME"))
+ return SortSectionPolicy::Name;
+ if (consume("SORT_BY_ALIGNMENT"))
+ return SortSectionPolicy::Alignment;
+ if (consume("SORT_BY_INIT_PRIORITY"))
+ return SortSectionPolicy::Priority;
+ if (consume("SORT_NONE"))
+ return SortSectionPolicy::None;
+ return SortSectionPolicy::Default;
+}
+
+// Reads SECTIONS command contents in the following form:
+//
+// <contents> ::= <elem>*
+// <elem> ::= <exclude>? <glob-pattern>
+// <exclude> ::= "EXCLUDE_FILE" "(" <glob-pattern>+ ")"
+//
+// For example,
+//
+// *(.foo EXCLUDE_FILE (a.o) .bar EXCLUDE_FILE (b.o) .baz)
+//
+// is parsed as ".foo", ".bar" with "a.o", and ".baz" with "b.o".
+// The semantics of that is section .foo in any file, section .bar in
+// any file but a.o, and section .baz in any file but b.o.
+std::vector<SectionPattern> ScriptParser::readInputSectionsList() {
+ std::vector<SectionPattern> Ret;
+ while (!Error && peek() != ")") {
+ StringMatcher ExcludeFilePat;
+ if (consume("EXCLUDE_FILE")) {
+ expect("(");
+ ExcludeFilePat = readFilePatterns();
+ }
+
+ std::vector<StringRef> V;
+ while (!Error && peek() != ")" && peek() != "EXCLUDE_FILE")
+ V.push_back(next());
+
+ if (!V.empty())
+ Ret.push_back({std::move(ExcludeFilePat), StringMatcher(V)});
+ else
+ setError("section pattern is expected");
+ }
+ return Ret;
+}
+
+// Reads contents of "SECTIONS" directive. That directive contains a
+// list of glob patterns for input sections. The grammar is as follows.
+//
+// <patterns> ::= <section-list>
+// | <sort> "(" <section-list> ")"
+// | <sort> "(" <sort> "(" <section-list> ")" ")"
+//
+// <sort> ::= "SORT" | "SORT_BY_NAME" | "SORT_BY_ALIGNMENT"
+// | "SORT_BY_INIT_PRIORITY" | "SORT_NONE"
+//
+// <section-list> is parsed by readInputSectionsList().
+InputSectionDescription *
+ScriptParser::readInputSectionRules(StringRef FilePattern) {
+ auto *Cmd = make<InputSectionDescription>(FilePattern);
+ expect("(");
+
+ while (!Error && !consume(")")) {
+ SortSectionPolicy Outer = readSortKind();
+ SortSectionPolicy Inner = SortSectionPolicy::Default;
+ std::vector<SectionPattern> V;
+ if (Outer != SortSectionPolicy::Default) {
+ expect("(");
+ Inner = readSortKind();
+ if (Inner != SortSectionPolicy::Default) {
+ expect("(");
+ V = readInputSectionsList();
+ expect(")");
+ } else {
+ V = readInputSectionsList();
}
- S = S.substr(E + 2);
- continue;
+ expect(")");
+ } else {
+ V = readInputSectionsList();
}
- if (S.startswith("#")) {
- size_t E = S.find('\n', 1);
- if (E == StringRef::npos)
- E = S.size() - 1;
- S = S.substr(E + 1);
- continue;
+
+ for (SectionPattern &Pat : V) {
+ Pat.SortInner = Inner;
+ Pat.SortOuter = Outer;
}
- size_t Size = S.size();
- S = S.ltrim();
- if (S.size() == Size)
- return S;
+
+ std::move(V.begin(), V.end(), std::back_inserter(Cmd->SectionPatterns));
}
+ return Cmd;
}
-// An erroneous token is handled as if it were the last token before EOF.
-bool ScriptParserBase::atEOF() { return Error || Tokens.size() == Pos; }
+InputSectionDescription *
+ScriptParser::readInputSectionDescription(StringRef Tok) {
+ // Input section wildcard can be surrounded by KEEP.
+ // https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#Input-Section-Keep
+ if (Tok == "KEEP") {
+ expect("(");
+ StringRef FilePattern = next();
+ InputSectionDescription *Cmd = readInputSectionRules(FilePattern);
+ expect(")");
+ Script->Opt.KeptSections.push_back(Cmd);
+ return Cmd;
+ }
+ return readInputSectionRules(Tok);
+}
+
+void ScriptParser::readSort() {
+ expect("(");
+ expect("CONSTRUCTORS");
+ expect(")");
+}
-StringRef ScriptParserBase::next() {
- if (Error)
- return "";
- if (atEOF()) {
- setError("unexpected EOF");
- return "";
+AssertCommand *ScriptParser::readAssert() {
+ return make<AssertCommand>(readAssertExpr());
+}
+
+Expr ScriptParser::readAssertExpr() {
+ expect("(");
+ Expr E = readExpr();
+ expect(",");
+ StringRef Msg = unquote(next());
+ expect(")");
+
+ return [=] {
+ if (!E().getValue())
+ error(Msg);
+ return Script->getDot();
+ };
+}
+
+// Reads a FILL(expr) command. We handle the FILL command as an
+// 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() {
+ expect("(");
+ uint32_t V = parseFill(next());
+ expect(")");
+ return V;
+}
+
+OutputSectionCommand *
+ScriptParser::readOutputSectionDescription(StringRef OutSec) {
+ OutputSectionCommand *Cmd = make<OutputSectionCommand>(OutSec);
+ Cmd->Location = getCurrentLocation();
+
+ // Read an address expression.
+ // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html
+ if (peek() != ":")
+ Cmd->AddrExpr = readExpr();
+
+ expect(":");
+
+ if (consume("AT"))
+ Cmd->LMAExpr = readParenExpr();
+ if (consume("ALIGN"))
+ Cmd->AlignExpr = readParenExpr();
+ if (consume("SUBALIGN"))
+ Cmd->SubalignExpr = readParenExpr();
+
+ // Parse constraints.
+ if (consume("ONLY_IF_RO"))
+ Cmd->Constraint = ConstraintKind::ReadOnly;
+ if (consume("ONLY_IF_RW"))
+ Cmd->Constraint = ConstraintKind::ReadWrite;
+ expect("{");
+
+ while (!Error && !consume("}")) {
+ StringRef Tok = next();
+ if (Tok == ";") {
+ // Empty commands are allowed. Do nothing here.
+ } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) {
+ Cmd->Commands.push_back(Assign);
+ } else if (BytesDataCommand *Data = readBytesDataCommand(Tok)) {
+ Cmd->Commands.push_back(Data);
+ } else if (Tok == "ASSERT") {
+ Cmd->Commands.push_back(readAssert());
+ expect(";");
+ } else if (Tok == "CONSTRUCTORS") {
+ // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
+ // by name. This is for very old file formats such as ECOFF/XCOFF.
+ // For ELF, we should ignore.
+ } else if (Tok == "FILL") {
+ Cmd->Filler = readFill();
+ } else if (Tok == "SORT") {
+ readSort();
+ } else if (peek() == "(") {
+ Cmd->Commands.push_back(readInputSectionDescription(Tok));
+ } else {
+ setError("unknown command " + Tok);
+ }
}
- return Tokens[Pos++];
+
+ if (consume(">"))
+ Cmd->MemoryRegionName = next();
+
+ Cmd->Phdrs = readOutputSectionPhdrs();
+
+ if (consume("="))
+ Cmd->Filler = parseFill(next());
+ else if (peek().startswith("="))
+ Cmd->Filler = parseFill(next().drop_front());
+
+ // Consume optional comma following output section command.
+ consume(",");
+
+ return Cmd;
}
-StringRef ScriptParserBase::peek() {
+// Parses a given string as a octal/decimal/hexadecimal number and
+// returns it as a big-endian number. Used for `=<fillexp>`.
+// https://sourceware.org/binutils/docs/ld/Output-Section-Fill.html
+//
+// 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) {
+ uint32_t V = 0;
+ if (Tok.getAsInteger(0, V))
+ setError("invalid filler expression: " + Tok);
+
+ uint32_t Buf;
+ write32be(&Buf, V);
+ return Buf;
+}
+
+SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) {
+ expect("(");
+ SymbolAssignment *Cmd = readAssignment(next());
+ Cmd->Provide = Provide;
+ Cmd->Hidden = Hidden;
+ expect(")");
+ expect(";");
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) {
+ SymbolAssignment *Cmd = nullptr;
+ if (peek() == "=" || peek() == "+=") {
+ Cmd = readAssignment(Tok);
+ expect(";");
+ } else if (Tok == "PROVIDE") {
+ Cmd = readProvideHidden(true, false);
+ } else if (Tok == "HIDDEN") {
+ Cmd = readProvideHidden(false, true);
+ } else if (Tok == "PROVIDE_HIDDEN") {
+ Cmd = readProvideHidden(true, true);
+ }
+ return Cmd;
+}
+
+SymbolAssignment *ScriptParser::readAssignment(StringRef Name) {
+ StringRef Op = next();
+ assert(Op == "=" || Op == "+=");
+ Expr E = readExpr();
+ if (Op == "+=") {
+ std::string Loc = getCurrentLocation();
+ E = [=] { return add(Script->getSymbolValue(Loc, Name), E()); };
+ }
+ return make<SymbolAssignment>(Name, E, getCurrentLocation());
+}
+
+// This is an operator-precedence parser to parse a linker
+// script expression.
+Expr ScriptParser::readExpr() {
+ // Our lexer is context-aware. Set the in-expression bit so that
+ // they apply different tokenization rules.
+ bool Orig = InExpr;
+ InExpr = true;
+ Expr E = readExpr1(readPrimary(), 0);
+ InExpr = Orig;
+ return E;
+}
+
+static Expr combine(StringRef Op, Expr L, Expr R) {
+ if (Op == "+")
+ return [=] { return add(L(), R()); };
+ if (Op == "-")
+ return [=] { return sub(L(), R()); };
+ if (Op == "*")
+ return [=] { return mul(L(), R()); };
+ if (Op == "/")
+ return [=] { return div(L(), R()); };
+ if (Op == "<<")
+ return [=] { return L().getValue() << R().getValue(); };
+ if (Op == ">>")
+ return [=] { return L().getValue() >> R().getValue(); };
+ if (Op == "<")
+ return [=] { return L().getValue() < R().getValue(); };
+ if (Op == ">")
+ return [=] { return L().getValue() > R().getValue(); };
+ if (Op == ">=")
+ return [=] { return L().getValue() >= R().getValue(); };
+ if (Op == "<=")
+ return [=] { return L().getValue() <= R().getValue(); };
+ if (Op == "==")
+ return [=] { return L().getValue() == R().getValue(); };
+ if (Op == "!=")
+ return [=] { return L().getValue() != R().getValue(); };
+ if (Op == "&")
+ return [=] { return bitAnd(L(), R()); };
+ if (Op == "|")
+ return [=] { return bitOr(L(), R()); };
+ llvm_unreachable("invalid operator");
+}
+
+// This is a part of the operator-precedence parser. This function
+// assumes that the remaining token stream starts with an operator.
+Expr ScriptParser::readExpr1(Expr Lhs, int MinPrec) {
+ while (!atEOF() && !Error) {
+ // Read an operator and an expression.
+ if (consume("?"))
+ return readTernary(Lhs);
+ StringRef Op1 = peek();
+ if (precedence(Op1) < MinPrec)
+ break;
+ skip();
+ Expr Rhs = readPrimary();
+
+ // Evaluate the remaining part of the expression first if the
+ // next operator has greater precedence than the previous one.
+ // For example, if we have read "+" and "3", and if the next
+ // operator is "