diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -137,7 +137,6 @@ uint64_t> callGraphProfile; bool allowMultipleDefinition; - bool allowShlibUndefined; bool androidPackDynRelocs; bool armHasBlx = false; bool armHasMovtMovw = false; @@ -247,6 +246,7 @@ SortSectionPolicy sortSection; StripPolicy strip; UnresolvedPolicy unresolvedSymbols; + UnresolvedPolicy unresolvedSymbolsInShlib; Target2Policy target2; ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default; BuildIdKind buildId = BuildIdKind::None; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -584,40 +584,58 @@ // Determines what we should do if there are remaining unresolved // symbols after the name resolution. -static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &args) { +static void setUnresolvedSymbolPolicy(opt::InputArgList &args) { UnresolvedPolicy errorOrWarn = args.hasFlag(OPT_error_unresolved_symbols, OPT_warn_unresolved_symbols, true) ? UnresolvedPolicy::ReportError : UnresolvedPolicy::Warn; + // -shared implies -unresolved-symbols=ignore-all because missing + // symbols are likely to be resolved at runtime. + bool diagRegular = !config->shared, diagShlib = !config->shared; - // Process the last of -unresolved-symbols, -no-undefined or -z defs. - for (auto *arg : llvm::reverse(args)) { + for (const opt::Arg *arg : 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; + if (s == "ignore-all") { + diagRegular = false; + diagShlib = false; + } else if (s == "ignore-in-object-files") { + diagRegular = false; + diagShlib = true; + } else if (s == "ignore-in-shared-libs") { + diagRegular = true; + diagShlib = false; + } else if (s == "report-all") { + diagRegular = true; + diagShlib = true; + } else { + error("unknown --unresolved-symbols value: " + s); + } + break; } case OPT_no_undefined: - return errorOrWarn; + diagRegular = true; + break; case OPT_z: if (StringRef(arg->getValue()) == "defs") - return errorOrWarn; - if (StringRef(arg->getValue()) == "undefs") - return UnresolvedPolicy::Ignore; - continue; + diagRegular = true; + else if (StringRef(arg->getValue()) == "undefs") + diagRegular = false; + break; + case OPT_allow_shlib_undefined: + diagShlib = false; + break; + case OPT_no_allow_shlib_undefined: + diagShlib = true; + break; } } - // -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; + config->unresolvedSymbols = + diagRegular ? errorOrWarn : UnresolvedPolicy::Ignore; + config->unresolvedSymbolsInShlib = + diagShlib ? errorOrWarn : UnresolvedPolicy::Ignore; } static Target2Policy getTarget2(opt::InputArgList &args) { @@ -913,9 +931,6 @@ args.hasFlag(OPT_allow_multiple_definition, OPT_no_allow_multiple_definition, false) || hasZOption(args, "muldefs"); - config->allowShlibUndefined = - args.hasFlag(OPT_allow_shlib_undefined, OPT_no_allow_shlib_undefined, - args.hasArg(OPT_shared)); config->auxiliaryList = args::getStrings(args, OPT_auxiliary); config->bsymbolic = args.hasArg(OPT_Bsymbolic); config->bsymbolicFunctions = args.hasArg(OPT_Bsymbolic_functions); @@ -1051,7 +1066,6 @@ config->unique = args.hasArg(OPT_unique); config->useAndroidRelrTags = args.hasFlag( OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); - config->unresolvedSymbols = getUnresolvedSymbolPolicy(args); config->warnBackrefs = args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); config->warnCommon = args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); @@ -1086,6 +1100,7 @@ config->zStartStopVisibility = getZStartStopVisibility(args); config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); + setUnresolvedSymbolPolicy(args); for (opt::Arg *arg : args.filtered(OPT_z)) { std::pair option = diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1988,7 +1988,7 @@ if (in.iplt && in.iplt->isNeeded()) in.iplt->addSymbols(); - if (!config->allowShlibUndefined) { + if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) { // Error on undefined symbols in a shared object, if all of its DT_NEEDED // entries are seen. These cases would otherwise lead to runtime errors // reported by the dynamic linker. @@ -2005,9 +2005,14 @@ for (Symbol *sym : symtab->symbols()) if (sym->isUndefined() && !sym->isWeak()) if (auto *f = dyn_cast_or_null(sym->file)) - if (f->allNeededIsKnown) - errorOrWarn(toString(f) + ": undefined reference to " + - toString(*sym) + " [--no-allow-shlib-undefined]"); + if (f->allNeededIsKnown) { + auto diagnose = config->unresolvedSymbolsInShlib == + UnresolvedPolicy::ReportError + ? errorOrWarn + : warn; + diagnose(toString(f) + ": undefined reference to " + + toString(*sym) + " [--no-allow-shlib-undefined]"); + } } { diff --git a/lld/test/ELF/allow-shlib-undefined.s b/lld/test/ELF/allow-shlib-undefined.s --- a/lld/test/ELF/allow-shlib-undefined.s +++ b/lld/test/ELF/allow-shlib-undefined.s @@ -9,7 +9,8 @@ # RUN: not ld.lld --no-allow-shlib-undefined %t.o %t.so -o /dev/null 2>&1 | FileCheck %s # Executable defaults to --no-allow-shlib-undefined # RUN: not ld.lld %t.o %t.so -o /dev/null 2>&1 | FileCheck %s -# RUN: ld.lld %t.o %t.so --noinhibit-exec -o /dev/null 2>&1 | FileCheck %s +# RUN: ld.lld %t.o %t.so --noinhibit-exec -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN +# RUN: ld.lld %t.o %t.so --warn-unresolved-symbols -o /dev/null 2>&1 | FileCheck %s --check-prefix=WARN # -shared defaults to --allow-shlib-undefined # RUN: ld.lld -shared %t.o %t.so -o /dev/null @@ -28,4 +29,5 @@ _start: callq _shared@PLT -# CHECK: {{.*}}.so: undefined reference to _unresolved [--no-allow-shlib-undefined] +# CHECK: error: {{.*}}.so: undefined reference to _unresolved [--no-allow-shlib-undefined] +# WARN: warning: {{.*}}.so: undefined reference to _unresolved [--no-allow-shlib-undefined] diff --git a/lld/test/ELF/unresolved-symbols.s b/lld/test/ELF/unresolved-symbols.s --- a/lld/test/ELF/unresolved-symbols.s +++ b/lld/test/ELF/unresolved-symbols.s @@ -33,9 +33,10 @@ ## 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 /dev/null --allow-shlib-undefined --unresolved-symbols=ignore-in-object-files -# RUN: llvm-readobj %t2 > /dev/null 2>&1 +## --unresolved-symbols overrides a previous --allow-shlib-undefined. +# RUN: not ld.lld %t1.o %t.so -o /dev/null --allow-shlib-undefined --unresolved-symbols=ignore-in-object-files 2>&1 | FileCheck %s --check-prefix=SHLIB + +# SHLIB: error: {{.*}}.so: undefined reference to undef [--no-allow-shlib-undefined] ## Ignoring undefines in shared should produce error for symbol from object. # RUN: not ld.lld %t2.o -o /dev/null --unresolved-symbols=ignore-in-shared-libs 2>&1 | \ @@ -53,11 +54,9 @@ # 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 +## report-all is the default when linking an executable. Check that we report +## unresolved undefines from both DSO and regular object files. +# RUN: not ld.lld -shared %t1.o %t.so -o /dev/null --unresolved-symbols=report-all 2>&1 | FileCheck %s --check-prefix=SHLIB # 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 /dev/null --unresolved-symbols=report-all 2>&1 | \