Skip to content

Commit

Permalink
[ELF] Fix interaction between --unresolved-symbols= and --[no-]allow-…
Browse files Browse the repository at this point in the history
…shlib-undefined

As mentioned in https://reviews.llvm.org/D67479#1667256 ,

* `--[no-]allow-shlib-undefined` control the diagnostic for an unresolved symbol in a shared object
* `-z defs/-z undefs` control the diagnostic for an unresolved symbol in a regular object file
* `--unresolved-symbols=` controls both bits.

In addition, make --warn-unresolved-symbols affect --no-allow-shlib-undefined.

This patch makes the behavior match GNU ld.

Reviewed By: psmith

Differential Revision: https://reviews.llvm.org/D91510
  • Loading branch information
MaskRay committed Nov 17, 2020
1 parent 0883497 commit 55d310a
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 38 deletions.
2 changes: 1 addition & 1 deletion lld/ELF/Config.h
Expand Up @@ -137,7 +137,6 @@ struct Configuration {
uint64_t>
callGraphProfile;
bool allowMultipleDefinition;
bool allowShlibUndefined;
bool androidPackDynRelocs;
bool armHasBlx = false;
bool armHasMovtMovw = false;
Expand Down Expand Up @@ -247,6 +246,7 @@ struct Configuration {
SortSectionPolicy sortSection;
StripPolicy strip;
UnresolvedPolicy unresolvedSymbols;
UnresolvedPolicy unresolvedSymbolsInShlib;
Target2Policy target2;
ARMVFPArgKind armVFPArgs = ARMVFPArgKind::Default;
BuildIdKind buildId = BuildIdKind::None;
Expand Down
61 changes: 38 additions & 23 deletions lld/ELF/Driver.cpp
Expand Up @@ -584,40 +584,58 @@ static std::string getRpath(opt::InputArgList &args) {

// 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) {
Expand Down Expand Up @@ -913,9 +931,6 @@ static void readConfigs(opt::InputArgList &args) {
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);
Expand Down Expand Up @@ -1051,7 +1066,6 @@ static void readConfigs(opt::InputArgList &args) {
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);
Expand Down Expand Up @@ -1086,6 +1100,7 @@ static void readConfigs(opt::InputArgList &args) {
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<StringRef, StringRef> option =
Expand Down
13 changes: 9 additions & 4 deletions lld/ELF/Writer.cpp
Expand Up @@ -1988,7 +1988,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
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.
Expand All @@ -2005,9 +2005,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (Symbol *sym : symtab->symbols())
if (sym->isUndefined() && !sym->isWeak())
if (auto *f = dyn_cast_or_null<SharedFile>(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]");
}
}

{
Expand Down
6 changes: 4 additions & 2 deletions lld/test/ELF/allow-shlib-undefined.s
Expand Up @@ -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

Expand All @@ -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]
15 changes: 7 additions & 8 deletions lld/test/ELF/unresolved-symbols.s
Expand Up @@ -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 | \
Expand All @@ -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 | \
Expand Down

0 comments on commit 55d310a

Please sign in to comment.