Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -33,6 +33,8 @@ enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; +enum HandlingRule { NoUndef, Error, Warn, Ignore }; + // This struct contains symbols version definition that // can be found in version script if it is used for link. struct Version { @@ -85,9 +87,7 @@ bool ICF; bool Mips64EL = false; bool NoGnuUnique; - bool NoUndefined; bool NoUndefinedVersion; - bool NoinhibitExec; bool Pic; bool Pie; bool PrintGcSections; @@ -110,6 +110,7 @@ bool ZNow; bool ZOrigin; bool ZRelro; + HandlingRule UnresolvedSymbols = Error; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -328,10 +328,7 @@ Config->GcSections = Args.hasArg(OPT_gc_sections); Config->ICF = Args.hasArg(OPT_icf); Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); - Config->NoUndefined = - Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs"); Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); - Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->Pie = Args.hasArg(OPT_pie); Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections); Config->Relocatable = Args.hasArg(OPT_relocatable); @@ -412,6 +409,22 @@ for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); + if (Args.hasArg(OPT_noinhibit_exec)) + Config->UnresolvedSymbols = Warn; + else if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs")) + Config->UnresolvedSymbols = NoUndef; + else if (Config->Relocatable) + Config->UnresolvedSymbols = Ignore; + else if (auto *Arg = Args.getLastArg(OPT_unresolved_symbols)) { + StringRef S = Arg->getValue(); + if (S == "ignore-all" || S == "ignore-in-object-files") + Config->UnresolvedSymbols = Ignore; + else if (S == "ignore-in-shared-libs" || S == "report-all") + Config->UnresolvedSymbols = Error; + else + error("unknown --unresolved-symbols value: " + S); + } + if (auto *Arg = Args.getLastArg(OPT_dynamic_list)) if (Optional Buffer = readFile(Arg->getValue())) parseDynamicList(*Buffer); Index: ELF/LTO.cpp =================================================================== --- ELF/LTO.cpp +++ ELF/LTO.cpp @@ -239,8 +239,8 @@ Keep.push_back(GV); } - if (Error E = Mover.move(Obj->takeModule(), Keep, - [](GlobalValue &, IRMover::ValueAdder) {})) { + if (llvm::Error E = Mover.move(Obj->takeModule(), Keep, + [](GlobalValue &, IRMover::ValueAdder) {})) { handleAllErrors(std::move(E), [&](const llvm::ErrorInfoBase &EIB) { fatal("failed to link module " + F.getName() + ": " + EIB.message()); }); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -150,6 +150,9 @@ def undefined: J<"undefined=">, HelpText<"Force undefined symbol during linking">; +def unresolved_symbols: J<"unresolved-symbols=">, + HelpText<"Determine how to handle unresolved symbols.">; + def verbose: F<"verbose">, HelpText<"Verbose mode">; def version: F<"version">, HelpText<"Display the version number">; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -9,6 +9,7 @@ #include "Writer.h" #include "Config.h" +#include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" #include "Relocations.h" @@ -275,17 +276,17 @@ template static void reportUndefined(SymbolTable &Symtab, SymbolBody *Sym) { - if (!Config->NoUndefined) { - if (Config->Relocatable) - return; + if (Config->UnresolvedSymbols == Ignore) + return; + + if (Config->UnresolvedSymbols != NoUndef) if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT) return; - } std::string Msg = "undefined symbol: " + Sym->getName().str(); if (InputFile *File = Sym->getSourceFile()) Msg += " in " + getFilename(File); - if (Config->NoinhibitExec) + if (Config->UnresolvedSymbols == Warn) warning(Msg); else error(Msg); Index: test/ELF/Inputs/unresolved-symbols.s =================================================================== --- test/ELF/Inputs/unresolved-symbols.s +++ test/ELF/Inputs/unresolved-symbols.s @@ -0,0 +1,3 @@ +.globl _shared +_shared: + callq undef@PLT Index: test/ELF/unresolved-symbols.s =================================================================== --- test/ELF/unresolved-symbols.s +++ test/ELF/unresolved-symbols.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/unresolved-symbols.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t.so + +## Check that %t2.o contains undefined symbol undef. +# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | \ +# RUN: FileCheck -check-prefix=UNDCHECK %s +# UNDCHECK: undefined symbol: undef in {{.*}}2.o + +## Error out if unknown option value was set. +# RUN: not ld.lld %t1.o %t2.o -o %t --unresolved-symbols=xxx 2>&1 | \ +# RUN: FileCheck -check-prefix=ERR1 %s +# ERR1: unknown --unresolved-symbols value: xxx + +## Ignore all should not produce error for symbols from object except +## case when --no-undefined specified. +# RUN: ld.lld %t2.o -o %t1_1 --unresolved-symbols=ignore-all +# RUN: llvm-readobj %t1_1 > /dev/null 2>&1 +# RUN: not ld.lld %t2.o -o %t1_2 --unresolved-symbols=ignore-all --no-undefined 2>&1 | \ +# RUN: FileCheck -check-prefix=ERRUND %s +# ERRUND: undefined symbol: undef +## Also ignore all should not produce error for symbols from DSOs. +# RUN: ld.lld %t1.o %t.so -o %t1_3 --unresolved-symbols=ignore-all +# RUN: llvm-readobj %t1_3 > /dev/null 2>&1 + +## Ignoring undefines in objects should not produce error for symbol from object. +# RUN: ld.lld %t1.o %t2.o -o %t2 --unresolved-symbols=ignore-in-object-files +# RUN: llvm-readobj %t2 > /dev/null 2>&1 +## And still should not should produce for undefines from DSOs. +# RUN: ld.lld %t1.o %t.so -o %t2_1 --unresolved-symbols=ignore-in-object-files +# RUN: llvm-readobj %t2 > /dev/null 2>&1 + +## Ignoring undefines in shared should produce error for symbol from object. +# RUN: not ld.lld %t2.o -o %t3 --unresolved-symbols=ignore-in-shared-libs 2>&1 | \ +# RUN: FileCheck -check-prefix=ERRUND %s +## And should not produce errors for symbols from DSO. +# RUN: ld.lld %t1.o %t.so -o %t3_1 --unresolved-symbols=ignore-in-shared-libs +# RUN: llvm-readobj %t3_1 > /dev/null 2>&1 + +## Ignoring undefines in shared libs should not produce error for symbol from object +## if we are linking DSO. +# RUN: ld.lld -shared %t1.o -o %t4 --unresolved-symbols=ignore-in-shared-libs +# RUN: llvm-readobj %t4 > /dev/null 2>&1 + +## Do not report undefines if linking relocatable. +# RUN: ld.lld -r %t1.o %t2.o -o %t5 --unresolved-symbols=report-all +# RUN: llvm-readobj %t5 > /dev/null 2>&1 + +## report-all is the default one. Check that we do not report +## undefines from DSO and do report undefines from object. With +## report-all specified and without. +# RUN: ld.lld -shared %t1.o %t.so -o %t6 --unresolved-symbols=report-all +# RUN: llvm-readobj %t6 > /dev/null 2>&1 +# RUN: ld.lld -shared %t1.o %t.so -o %t6_1 +# RUN: llvm-readobj %t6_1 > /dev/null 2>&1 +# RUN: not ld.lld %t2.o -o %t7 --unresolved-symbols=report-all 2>&1 | \ +# RUN: FileCheck -check-prefix=ERRUND %s +# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | \ +# RUN: FileCheck -check-prefix=ERRUND %s + +.globl _start +_start: