Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -44,7 +44,7 @@ enum class StripPolicy { None, All, Debug }; // For --unresolved-symbols. -enum class UnresolvedPolicy { ReportError, Warn, WarnAll, Ignore, IgnoreAll }; +enum class UnresolvedPolicy { ReportError, Warn, Ignore, IgnoreAll }; // For --sort-section and linkerscript sorting rules. enum class SortSectionPolicy { Default, None, Alignment, Name, Priority }; @@ -128,6 +128,7 @@ bool ICF; bool MipsN32Abi = false; bool NoGnuUnique; + bool NoinhibitExec; bool NoUndefinedVersion; bool Nostdlib; bool OFormatBinary; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -418,9 +418,6 @@ // Determines what we should do if there are remaining unresolved // symbols after the name resolution. static UnresolvedPolicy getUnresolvedSymbolPolicy(opt::InputArgList &Args) { - // -noinhibit-exec or -r imply some default values. - if (Args.hasArg(OPT_noinhibit_exec)) - return UnresolvedPolicy::WarnAll; if (Args.hasArg(OPT_relocatable)) return UnresolvedPolicy::IgnoreAll; @@ -647,6 +644,7 @@ Config->LTOPartitions = getInteger(Args, OPT_lto_partitions, 1); Config->MapFile = Args.getLastArgValue(OPT_Map); Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); + Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); Config->Nostdlib = Args.hasArg(OPT_nostdlib); Config->OFormatBinary = isOutputFormatBinary(Args); Index: ELF/Error.cpp =================================================================== --- ELF/Error.cpp +++ ELF/Error.cpp @@ -82,6 +82,11 @@ } void elf::error(const Twine &Msg) { + if (Config->NoinhibitExec) { + warn(Msg); + return; + } + std::lock_guard Lock(Mu); newline(Msg); Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -678,8 +678,7 @@ if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) return; - bool CanBeExternal = Sym.symbol()->computeBinding() != STB_LOCAL && - Sym.getVisibility() == STV_DEFAULT; + bool CanBeExternal = Sym.symbol()->canBeExternal(); if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return; @@ -691,12 +690,10 @@ Msg += Src + "\n>>> "; Msg += S.getObjMsg(Offset); - if (Config->UnresolvedSymbols == UnresolvedPolicy::WarnAll || - (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal)) { + if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) warn(Msg); - } else { + else error(Msg); - } } template Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -369,6 +369,7 @@ unsigned InVersionScript : 1; bool includeInDynsym() const; + bool canBeExternal() const; uint8_t computeBinding() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -141,10 +141,6 @@ if (isShared()) return !NeedsCopy && !NeedsPltAddr; - // That's all that can be preempted in a non-DSO. - if (!Config->Shared) - return false; - // Only symbols that appear in dynsym can be preempted. if (!symbol()->includeInDynsym()) return false; @@ -153,6 +149,12 @@ if (symbol()->Visibility != STV_DEFAULT) return false; + // Undefined external symbols in a non-DSO usually reported by linker and link + // fails, but together with --unresolved-symbols=ignore-all link succeeds and + // runtime linker should take care about them during execution. + if (!Config->Shared) + return isUndefined(); + // -Bsymbolic means that definitions are not preempted. if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc())) return !isDefined(); @@ -354,11 +356,21 @@ return Binding; } +bool Symbol::canBeExternal() const { + return computeBinding() != STB_LOCAL && + body()->getVisibility() == STV_DEFAULT; +} + bool Symbol::includeInDynsym() const { if (computeBinding() == STB_LOCAL) return false; - return ExportDynamic || body()->isShared() || - (body()->isUndefined() && Config->Shared); + if (ExportDynamic || body()->isShared()) + return true; + if (!body()->isUndefined()) + return false; + if (Config->Shared) + return true; + return canBeExternal() && !body()->symbol()->isWeak(); } // Print out a log message for --trace-symbol. Index: test/ELF/executable-undefined-ignoreall.s =================================================================== --- test/ELF/executable-undefined-ignoreall.s +++ test/ELF/executable-undefined-ignoreall.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %tout --unresolved-symbols=ignore-all -pie +# RUN: llvm-readobj -r %tout | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section ({{.*}}) .rela.plt { +# CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +_start: +callq foo@PLT Index: test/ELF/no-inhibit-exec.s =================================================================== --- test/ELF/no-inhibit-exec.s +++ test/ELF/no-inhibit-exec.s @@ -6,7 +6,7 @@ # CHECK: Disassembly of section .text: # CHECK-NEXT: _start -# CHECK-NEXT: 201000: {{.*}} callq -2101253 +# CHECK-NEXT: 201000: {{.*}} callq 0 # next code will not link without noinhibit-exec flag # because of undefined symbol _bar