aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Rimar <grimar@accesssoftek.com>2016-06-29 12:35:04 +0000
committerGeorge Rimar <grimar@accesssoftek.com>2016-06-29 12:35:04 +0000
commitb752e4b82f19d7d55e0a3f59f8553a208976081f (patch)
tree0f729d24359caa7acee6b3372f379ba5e84dbec7
parent7afe2b6e755f7e486762e1f1de61f8a94aae5b3f (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.h5
-rw-r--r--ELF/Driver.cpp24
-rw-r--r--ELF/Options.td3
-rw-r--r--ELF/Writer.cpp14
-rw-r--r--test/ELF/Inputs/unresolved-symbols.s3
-rw-r--r--test/ELF/unresolved-symbols.s63
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: