Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -151,6 +151,7 @@ bool Verbose; bool WarnCommon; bool WarnMissingEntry; + bool WarnSymbolOrdering; bool ZCombreloc; bool ZExecstack; bool ZNocopyreloc; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -670,6 +670,8 @@ Config->Verbose = Args.hasArg(OPT_verbose); errorHandler().Verbose = Config->Verbose; Config->WarnCommon = Args.hasArg(OPT_warn_common); + Config->WarnSymbolOrdering = + Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); Config->ZExecstack = hasZOption(Args, "execstack"); Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc"); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -208,6 +208,9 @@ def no_threads: F<"no-threads">, HelpText<"Do not run the linker multi-threaded">; +def no_warn_symbol_ordering: F<"no-warn-symbol-ordering">, + HelpText<"Do not warn about problems with the symbol ordering file">; + def no_whole_archive: F<"no-whole-archive">, HelpText<"Restores the default behavior of loading archive members">; @@ -323,6 +326,9 @@ def warn_common: F<"warn-common">, HelpText<"Warn about duplicate common symbols">; +def warn_symbol_ordering: F<"warn-symbol-ordering">, + HelpText<"Warn about problems with the symbol ordering file">; + def warn_unresolved_symbols: F<"warn-unresolved-symbols">, HelpText<"Report unresolved symbols as warnings">; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -1029,21 +1029,54 @@ // Build a map from symbols to their priorities. Symbols that didn't // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. - DenseMap SymbolOrder; + // The values are of the form {priority, present in inputs}. + DenseMap> SymbolOrder; int Priority = -Config->SymbolOrderingFile.size(); - for (StringRef S : Config->SymbolOrderingFile) - SymbolOrder.insert({S, Priority++}); + for (StringRef S : Config->SymbolOrderingFile) { + auto Inserted = SymbolOrder.insert({S, {Priority++, false}}); + if (Config->WarnSymbolOrdering && !Inserted.second) + warn("symbol ordering file: symbol '" + S + "' specified multiple times"); + } // Build a map from sections to their priorities. for (InputFile *File : ObjectFiles) { for (Symbol *Sym : File->getSymbols()) { auto *D = dyn_cast(Sym); + auto OrderEntry = SymbolOrder.find(Sym->getName()); + if (Config->WarnSymbolOrdering && OrderEntry != SymbolOrder.end()) { + if (Sym->isUndefined()) + warn("symbol ordering file: unable to order undefined symbol '" + + Sym->getName() + "' from file '" + File->getName() + "'"); + else if (Sym->isShared()) + warn("symbol ordering file: unable to order shared symbol '" + + Sym->getName() + "' from file '" + File->getName() + "'"); + else if (D && !D->Section) + warn("symbol ordering file: unable to order absolute symbol '" + + Sym->getName() + "' from file '" + File->getName() + "'"); + else if (D && !D->Section->Live) + warn("symbol ordering file: unable to order discarded symbol '" + + Sym->getName() + "' from file '" + File->getName() + "'"); + OrderEntry->second.second = true; + } if (!D || !D->Section) continue; + int &Priority = SectionOrder[D->Section]; - Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); + int OrderPriority = 0; + if (OrderEntry != SymbolOrder.end()) + OrderPriority = OrderEntry->second.first; + Priority = std::min(Priority, OrderPriority); } } + + if (Config->WarnSymbolOrdering) + for (auto V : SymbolOrder) { + bool Used = V.second.second; + if (!Used) + warn("symbol ordering file: no symbol '" + V.first + + "' found in input"); + } + return SectionOrder; } Index: test/ELF/Inputs/symbol-ordering-file-warnings1.s =================================================================== --- test/ELF/Inputs/symbol-ordering-file-warnings1.s +++ test/ELF/Inputs/symbol-ordering-file-warnings1.s @@ -0,0 +1,19 @@ +# This is a "bad" (absolute) instance of the symbol +multi = 1234 + +.text +.global shared +.type shared, @function +shared: + movq %rax, multi + ret + +.section .text.comdat,"axG",@progbits,comdat,comdat +.weak comdat +comdat: + ret + +.section .text.glob_or_wk,"ax",@progbits +.global glob_or_wk +glob_or_wk: + ret Index: test/ELF/Inputs/symbol-ordering-file-warnings2.s =================================================================== --- test/ELF/Inputs/symbol-ordering-file-warnings2.s +++ test/ELF/Inputs/symbol-ordering-file-warnings2.s @@ -0,0 +1,6 @@ +.text +.global missing +missing: + callq undefined + # This is a "bad" (undefined) instance of the symbol + callq multi Index: test/ELF/symbol-ordering-file-warnings.s =================================================================== --- test/ELF/symbol-ordering-file-warnings.s +++ test/ELF/symbol-ordering-file-warnings.s @@ -0,0 +1,141 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symbol-ordering-file-warnings1.s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symbol-ordering-file-warnings2.s -o %t2.o +# RUN: ld.lld -shared %t1.o -o %t.so + +# Check that a warning is emitted for entries in the file that are not present in any used input. +# RUN: echo "missing" > %t-order-missing.txt +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-missing.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,MISSING + +# Check that the warning can be disabled. +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-missing.txt --unresolved-symbols=ignore-all --no-warn-symbol-ordering 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that the warning can be re-enabled +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-missing.txt --unresolved-symbols=ignore-all --no-warn-symbol-ordering --warn-symbol-ordering 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,MISSING + +# Check that a warning is emitted for undefined symbols. +# RUN: echo "undefined" > %t-order-undef.txt +# RUN: ld.lld %t.o %t2.o -o %t --symbol-ordering-file %t-order-undef.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,UNDEFINED + +# Check that a warning is emitted for imported shared symbols. +# RUN: echo "shared" > %t-order-shared.txt +# RUN: ld.lld %t.o %t.so -o %t --symbol-ordering-file %t-order-shared.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,SHARED + +# Check that a warning is emitted for absolute symbols. +# RUN: echo "absolute" > %t-order-absolute.txt +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-absolute.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,ABSOLUTE + +# Check that a warning is emitted for symbols discarded due to --gc-sections. +# RUN: echo "gc" > %t-order-gc.txt +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-gc.txt --gc-sections --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,GC + +# Check that a warning is emitted for symbols discarded due to a linker script /DISCARD/ section. +# RUN: echo "discard" > %t-order-discard.txt +# RUN: echo "SECTIONS { /DISCARD/ : { *(.text.discard) } }" > %t.script +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-discard.txt -T %t.script --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,DISCARD + +# Check that LLD does not warn for discarded COMDAT symbols, if at least instance was kept. +# RUN: echo "comdat" > %t-order-comdat.txt +# RUN: ld.lld %t.o %t1.o -o %t --symbol-ordering-file %t-order-comdat.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that if a COMDAT was unused and discarded via --gc-sections, warn for each instance. +# RUN: ld.lld %t.o %t1.o -o %t --symbol-ordering-file %t-order-comdat.txt --gc-sections --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,COMDAT + +# Check that if a weak symbol is not kept, because of an equivalent global symbol, no warning is emitted. +# RUN: echo "glob_or_wk" > %t-order-weak.txt +# RUN: ld.lld %t.o %t1.o -o %t --symbol-ordering-file %t-order-weak.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that symbols only in unused archive members result in a warning. +# RUN: rm -f %t.a +# RUN: llvm-ar rc %t.a %t2.o +# RUN: ld.lld %t.o %t.a -o %t --symbol-ordering-file %t-order-missing.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,MISSING --allow-empty + +# Check that a warning for each same-named symbol with an issue. +# RUN: echo "multi" > %t-order-same-name.txt +# RUN: ld.lld %t.o %t1.o %t2.o -o %t --symbol-ordering-file %t-order-same-name.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,MULTI + +# Check that a warning is emitted if the same symbol is mentioned multiple times in the ordering file. +# RUN: echo "_start" > %t-order-multiple-same.txt +# RUN: echo "_start" >> %t-order-multiple-same.txt +# RUN: ld.lld %t.o -o %t --symbol-ordering-file %t-order-multiple-same.txt --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,SAMESYM + +# Check that all warnings can be emitted from the same input. +# RUN: echo "missing_sym" > %t-order-multi.txt +# RUN: echo "undefined" >> %t-order-multi.txt +# RUN: echo "_start" >> %t-order-multi.txt +# RUN: echo "shared" >> %t-order-multi.txt +# RUN: echo "absolute" >> %t-order-multi.txt +# RUN: echo "gc" >> %t-order-multi.txt +# RUN: echo "discard" >> %t-order-multi.txt +# RUN: echo "_start" >> %t-order-multi.txt +# RUN: ld.lld %t.o %t2.o %t.so -o %t --symbol-ordering-file %t-order-multi.txt --gc-sections -T %t.script --unresolved-symbols=ignore-all 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,SAMESYM,ABSOLUTE,SHARED,UNDEFINED,GC,DISCARD,MISSING2 + +# WARN-NOT: warning: +# SAMESYM: warning: symbol ordering file: symbol '_start' specified multiple times +# WARN-NOT: warning: +# ABSOLUTE: warning: symbol ordering file: unable to order absolute symbol 'absolute' from file +# WARN-NOT: warning: +# DISCARD: warning: symbol ordering file: unable to order discarded symbol 'discard' from file +# WARN-NOT: warning: +# GC: warning: symbol ordering file: unable to order discarded symbol 'gc' from file +# WARN-NOT: warning: +# SHARED: warning: symbol ordering file: unable to order shared symbol 'shared' from file +# WARN-NOT: warning: +# UNDEFINED: warning: symbol ordering file: unable to order undefined symbol 'undefined' from file +# WARN-NOT: warning: +# MISSING: warning: symbol ordering file: no symbol 'missing' found in input +# MISSING2: warning: symbol ordering file: no symbol 'missing_sym' found in input +# COMDAT: warning: symbol ordering file: unable to order discarded symbol 'comdat' from file +# COMDAT-NEXT: warning: symbol ordering file: unable to order discarded symbol 'comdat' from file +# MULTI: warning: symbol ordering file: unable to order absolute symbol 'multi' from file +# MULTI-NEXT: warning: symbol ordering file: unable to order undefined symbol 'multi' from file +# WARN-NOT: warning: + +absolute = 0x1234 +.global absolute + +.section .text.gc,"ax",@progbits +.global gc +gc: + nop + +.section .text.discard,"ax",@progbits +.global discard +discard: + nop + +.section .text.comdat,"axG",@progbits,comdat,comdat +.weak comdat +comdat: + nop + +.section .text.glob_or_wk,"ax",@progbits +.weak glob_or_wk +glob_or_wk: + nop + +.text +.global _start +_start: + movq %rax, absolute + callq shared + +# This is a "good" instance of the symbol +multi: + nop