diff options
author | George Rimar <grimar@accesssoftek.com> | 2016-06-29 12:35:04 +0000 |
---|---|---|
committer | George Rimar <grimar@accesssoftek.com> | 2016-06-29 12:35:04 +0000 |
commit | b752e4b82f19d7d55e0a3f59f8553a208976081f (patch) | |
tree | 0f729d24359caa7acee6b3372f379ba5e84dbec7 | |
parent | 7afe2b6e755f7e486762e1f1de61f8a94aae5b3f (diff) |
[ELF] - Added support for --unresolved-symbols option.
Option has next description (http://linux.die.net/man/1/ld):
"--unresolved-symbols=method
Determine how to handle unresolved symbols. There are four possible values for method
according to documentation:
ignore-all: Do not report any unresolved symbols.
report-all: Report all unresolved symbols. This is the default.
ignore-in-object-files: Report unresolved symbols that are contained in shared libraries, but ignore them if they come from regular object files.
ignore-in-shared-libs: Report unresolved symbols that come from regular object files, but ignore them if they come from shared libraries."
Since report-all is default and we traditionally do not report about undefined symbols in lld,
report-all does not report about undefines from DSO.
ignore-in-object-files also does not do that. Handling of that option differs from what gnu linkers do.
Option works in next way in lld:
ignore-all: Do not report any unresolved symbols.
report-all: Report all unresolved symbols except symbols from DSOs. This is the default.
ignore-in-object-files: The same as ignore-all.
gnore-in-shared-libs: The same as report-all.
This is PR24524.
Differential revision: http://reviews.llvm.org/D21794
git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@274123 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | ELF/Config.h | 5 | ||||
-rw-r--r-- | ELF/Driver.cpp | 24 | ||||
-rw-r--r-- | ELF/Options.td | 3 | ||||
-rw-r--r-- | ELF/Writer.cpp | 14 | ||||
-rw-r--r-- | test/ELF/Inputs/unresolved-symbols.s | 3 | ||||
-rw-r--r-- | test/ELF/unresolved-symbols.s | 63 |
6 files changed, 100 insertions, 12 deletions
diff --git a/ELF/Config.h b/ELF/Config.h index 703dedfaa..a12ff35c4 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -33,6 +33,8 @@ enum ELFKind { enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring }; +enum class UnresolvedPolicy { 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 @@ struct Configuration { bool ICF; bool Mips64EL = false; bool NoGnuUnique; - bool NoUndefined; bool NoUndefinedVersion; - bool NoinhibitExec; bool Pic; bool Pie; bool PrintGcSections; @@ -110,6 +110,7 @@ struct Configuration { bool ZNow; bool ZOrigin; bool ZRelro; + UnresolvedPolicy UnresolvedSymbols; BuildIdKind BuildId = BuildIdKind::None; ELFKind EKind = ELFNoneKind; uint16_t EMachine = llvm::ELF::EM_NONE; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index e614db026..c8041e0db 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -296,6 +296,25 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { } } +static UnresolvedPolicy getUnresolvedSymbolOption(opt::InputArgList &Args) { + if (Args.hasArg(OPT_noinhibit_exec)) + return UnresolvedPolicy::Warn; + if (Args.hasArg(OPT_no_undefined) || hasZOption(Args, "defs")) + return UnresolvedPolicy::NoUndef; + if (Config->Relocatable) + return UnresolvedPolicy::Ignore; + + if (auto *Arg = Args.getLastArg(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 UnresolvedPolicy::Error; + error("unknown --unresolved-symbols value: " + S); + } + return UnresolvedPolicy::Error; +} + // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_L)) @@ -328,10 +347,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { 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 +428,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { for (auto *Arg : Args.filtered(OPT_undefined)) Config->Undefined.push_back(Arg->getValue()); + Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args); + if (auto *Arg = Args.getLastArg(OPT_dynamic_list)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) parseDynamicList(*Buffer); diff --git a/ELF/Options.td b/ELF/Options.td index c224eef57..857e620ad 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -150,6 +150,9 @@ def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">; 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">; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 323a791c3..28036d3db 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -275,17 +275,17 @@ template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> { template <class ELFT> static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) { - if (!Config->NoUndefined) { - if (Config->Relocatable) - return; - if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT) - return; - } + if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore) + return; + + if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT && + Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef) + return; std::string Msg = "undefined symbol: " + Sym->getName().str(); if (InputFile *File = Sym->getSourceFile<ELFT>()) Msg += " in " + getFilename(File); - if (Config->NoinhibitExec) + if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn) warning(Msg); else error(Msg); diff --git a/test/ELF/Inputs/unresolved-symbols.s b/test/ELF/Inputs/unresolved-symbols.s new file mode 100644 index 000000000..b504708e4 --- /dev/null +++ b/test/ELF/Inputs/unresolved-symbols.s @@ -0,0 +1,3 @@ +.globl _shared +_shared: + callq undef@PLT diff --git a/test/ELF/unresolved-symbols.s b/test/ELF/unresolved-symbols.s new file mode 100644 index 000000000..2fa59cb0f --- /dev/null +++ b/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: |