Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -180,6 +180,7 @@ bool WarnCommon; bool WarnIfuncTextrel; bool WarnMissingEntry; + bool WarnOnce = false; bool WarnSymbolOrdering; bool WriteAddends; bool ZCombreloc; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -1107,6 +1107,9 @@ Files.back()->JustSymbols = true; } break; + case OPT_warn_once: + Config->WarnOnce = true; + break; case OPT_start_group: if (InputFile::IsInGroup) error("nested --start-group"); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -372,6 +372,8 @@ def warn_unresolved_symbols: F<"warn-unresolved-symbols">, HelpText<"Report unresolved symbols as warnings">; +def warn_once: F<"warn-once">, + HelpText<"Warn only once per undefined symbol">; defm whole_archive: B<"whole-archive", "Force load of all members in a static library", @@ -505,7 +507,6 @@ def: F<"sort-common">; def: F<"stats">; def: F<"warn-execstack">; -def: F<"warn-once">; def: F<"warn-shared-textrel">; def: F<"EB">; def: F<"EL">; Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -655,6 +655,12 @@ if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return false; + if (Config->WarnOnce) { + if (Sym.IsWarned) + return false; + Sym.IsWarned = true; + } + std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -184,7 +184,7 @@ Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), IsInIplt(false), IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), NeedsTocRestore(false), - ScriptDefined(false) {} + ScriptDefined(false), IsWarned(false) {} public: // True the symbol should point to its PLT entry. @@ -210,6 +210,9 @@ // True if this symbol is defined by a linker script. unsigned ScriptDefined : 1; + // True if this symbol is already reported as undefined + unsigned IsWarned : 1; + bool isSection() const { return Type == llvm::ELF::STT_SECTION; } bool isTls() const { return Type == llvm::ELF::STT_TLS; } bool isFunc() const { return Type == llvm::ELF::STT_FUNC; } Index: test/ELF/warn-once.s =================================================================== --- test/ELF/warn-once.s +++ test/ELF/warn-once.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld -warn-once %t.o -o %t.exe 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo +# CHECK-NEXT: >>> referenced by warn-once.s +# CHECK-NEXT: {{.*}}:(.text+0x1) +# CHECK-EMPTY: +# CHECK-NOT: error: undefined symbol: foo +# CHECK-NOT: >>> referenced by warn-once.s +# CHECK-NOT: {{.*}}:(.text+0x6) + +.file "warn-once.s" + + .globl _start +_start: + call foo + call foo; \ No newline at end of file