forked from OSchip/llvm-project
[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 llvm-svn: 274123
This commit is contained in:
parent
e5b3aebfb5
commit
e86dcd0cbd
|
|
@ -33,6 +33,8 @@ enum ELFKind {
|
||||||
|
|
||||||
enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
|
enum class BuildIdKind { None, Fnv1, Md5, Sha1, Hexstring };
|
||||||
|
|
||||||
|
enum class UnresolvedPolicy { NoUndef, Error, Warn, Ignore };
|
||||||
|
|
||||||
// This struct contains symbols version definition that
|
// This struct contains symbols version definition that
|
||||||
// can be found in version script if it is used for link.
|
// can be found in version script if it is used for link.
|
||||||
struct Version {
|
struct Version {
|
||||||
|
|
@ -85,9 +87,7 @@ struct Configuration {
|
||||||
bool ICF;
|
bool ICF;
|
||||||
bool Mips64EL = false;
|
bool Mips64EL = false;
|
||||||
bool NoGnuUnique;
|
bool NoGnuUnique;
|
||||||
bool NoUndefined;
|
|
||||||
bool NoUndefinedVersion;
|
bool NoUndefinedVersion;
|
||||||
bool NoinhibitExec;
|
|
||||||
bool Pic;
|
bool Pic;
|
||||||
bool Pie;
|
bool Pie;
|
||||||
bool PrintGcSections;
|
bool PrintGcSections;
|
||||||
|
|
@ -110,6 +110,7 @@ struct Configuration {
|
||||||
bool ZNow;
|
bool ZNow;
|
||||||
bool ZOrigin;
|
bool ZOrigin;
|
||||||
bool ZRelro;
|
bool ZRelro;
|
||||||
|
UnresolvedPolicy UnresolvedSymbols;
|
||||||
BuildIdKind BuildId = BuildIdKind::None;
|
BuildIdKind BuildId = BuildIdKind::None;
|
||||||
ELFKind EKind = ELFNoneKind;
|
ELFKind EKind = ELFNoneKind;
|
||||||
uint16_t EMachine = llvm::ELF::EM_NONE;
|
uint16_t EMachine = llvm::ELF::EM_NONE;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// Initializes Config members by the command line options.
|
||||||
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
||||||
for (auto *Arg : Args.filtered(OPT_L))
|
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->GcSections = Args.hasArg(OPT_gc_sections);
|
||||||
Config->ICF = Args.hasArg(OPT_icf);
|
Config->ICF = Args.hasArg(OPT_icf);
|
||||||
Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique);
|
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->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version);
|
||||||
Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec);
|
|
||||||
Config->Pie = Args.hasArg(OPT_pie);
|
Config->Pie = Args.hasArg(OPT_pie);
|
||||||
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
|
Config->PrintGcSections = Args.hasArg(OPT_print_gc_sections);
|
||||||
Config->Relocatable = Args.hasArg(OPT_relocatable);
|
Config->Relocatable = Args.hasArg(OPT_relocatable);
|
||||||
|
|
@ -412,6 +428,8 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {
|
||||||
for (auto *Arg : Args.filtered(OPT_undefined))
|
for (auto *Arg : Args.filtered(OPT_undefined))
|
||||||
Config->Undefined.push_back(Arg->getValue());
|
Config->Undefined.push_back(Arg->getValue());
|
||||||
|
|
||||||
|
Config->UnresolvedSymbols = getUnresolvedSymbolOption(Args);
|
||||||
|
|
||||||
if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
|
if (auto *Arg = Args.getLastArg(OPT_dynamic_list))
|
||||||
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue()))
|
||||||
parseDynamicList(*Buffer);
|
parseDynamicList(*Buffer);
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,9 @@ def trace_symbol : J<"trace-symbol=">, HelpText<"Trace references to symbols">;
|
||||||
def undefined: J<"undefined=">,
|
def undefined: J<"undefined=">,
|
||||||
HelpText<"Force undefined symbol during linking">;
|
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 verbose: F<"verbose">, HelpText<"Verbose mode">;
|
||||||
|
|
||||||
def version: F<"version">, HelpText<"Display the version number">;
|
def version: F<"version">, HelpText<"Display the version number">;
|
||||||
|
|
|
||||||
|
|
@ -275,17 +275,17 @@ template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
|
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
|
||||||
if (!Config->NoUndefined) {
|
if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore)
|
||||||
if (Config->Relocatable)
|
return;
|
||||||
return;
|
|
||||||
if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT)
|
if (Config->Shared && Sym->symbol()->Visibility == STV_DEFAULT &&
|
||||||
return;
|
Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef)
|
||||||
}
|
return;
|
||||||
|
|
||||||
std::string Msg = "undefined symbol: " + Sym->getName().str();
|
std::string Msg = "undefined symbol: " + Sym->getName().str();
|
||||||
if (InputFile *File = Sym->getSourceFile<ELFT>())
|
if (InputFile *File = Sym->getSourceFile<ELFT>())
|
||||||
Msg += " in " + getFilename(File);
|
Msg += " in " + getFilename(File);
|
||||||
if (Config->NoinhibitExec)
|
if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn)
|
||||||
warning(Msg);
|
warning(Msg);
|
||||||
else
|
else
|
||||||
error(Msg);
|
error(Msg);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.globl _shared
|
||||||
|
_shared:
|
||||||
|
callq undef@PLT
|
||||||
|
|
@ -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:
|
||||||
Loading…
Reference in New Issue