Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -25,6 +25,7 @@ bool DiscardNone = false; bool ExportDynamic = false; bool NoInhibitExec = false; + bool AllowShlibUndefines = false; }; extern Configuration *Config; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -79,8 +79,10 @@ if (!RPaths.empty()) Config->RPath = llvm::join(RPaths.begin(), RPaths.end(), ":"); - if (Args.hasArg(OPT_shared)) + if (Args.hasArg(OPT_shared)) { Config->Shared = true; + Config->AllowShlibUndefines = true; + } if (Args.hasArg(OPT_discard_all)) Config->DiscardAll = true; @@ -97,6 +99,12 @@ if (Args.hasArg(OPT_noinhibit_exec)) Config->NoInhibitExec = true; + if (auto *arg = Args.getLastArg(OPT_allow_shlib_undefined, + OPT_no_allow_shlib_undefined)) { + Config->AllowShlibUndefines = + arg->getOption().getID() == OPT_allow_shlib_undefined; + } + // Create a list of input files. std::vector Inputs; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -11,6 +11,7 @@ #include "InputSection.h" #include "Error.h" #include "Symbols.h" +#include "Writer.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -227,13 +228,13 @@ uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end()); SymbolBodies.reserve(NumSymbols); for (const Elf_Sym &Sym : Syms) { - if (Sym.isUndefined()) - continue; - ErrorOr NameOrErr = Sym.getName(this->StringTable); error(NameOrErr.getError()); StringRef Name = *NameOrErr; - + if (Sym.isUndefined()) { + undefError(Name, getName()); + continue; + } SymbolBodies.emplace_back(Name, Sym); } } Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -37,3 +37,12 @@ def export_dynamic : Flag<["--"], "export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; + +def no_allow_shlib_undefined + : Flag<["--"], "no-allow-shlib-undefined">, + HelpText<"Do not allow undefined symbols from dynamic" + " library when creating executables">; + +def allow_shlib_undefined : Flag<["--"], "allow-shlib-undefined">, + HelpText<"Allow undefined symbols from dynamic" + " library when creating executables">; Index: ELF/Writer.h =================================================================== --- ELF/Writer.h +++ ELF/Writer.h @@ -10,6 +10,10 @@ #ifndef LLD_ELF_WRITER_H #define LLD_ELF_WRITER_H +namespace llvm { +class Twine; +} + namespace lld { namespace elf2 { @@ -18,6 +22,8 @@ template void writeResult(SymbolTable *Symtab); +void undefError(const llvm::Twine &Symbol, const llvm::Twine &SymFile); + } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -171,6 +171,19 @@ template void writeResult(SymbolTable *); template void writeResult(SymbolTable *); +void undefError(const Twine &Symbol, const Twine &SymFile) { + if (Config->AllowShlibUndefines) + return; + + std::string Message = Twine("undefined symbol: " + Symbol).str(); + if (!SymFile.isTriviallyEmpty()) + Message = Twine(Message.c_str() + Twine(" in ") + SymFile).str(); + if (Config->NoInhibitExec) + warning(Message); + else + error(Message); +} + } // namespace elf2 } // namespace lld @@ -282,13 +295,7 @@ SymFile = F.get(); } - std::string Message = "undefined symbol: " + Sym.getName().str(); - if (SymFile) - Message += " in " + SymFile->getName().str(); - if (Config->NoInhibitExec) - warning(Message); - else - error(Message); + undefError(Sym.getName(), SymFile ? SymFile->getName() : ""); } // Create output section objects and add them to OutputSections. Index: test/elf2/Inputs/allow-shlib-undefined.s =================================================================== --- test/elf2/Inputs/allow-shlib-undefined.s +++ test/elf2/Inputs/allow-shlib-undefined.s @@ -0,0 +1,3 @@ +.globl _shared +_shared: + call _unresolved Index: test/elf2/allow-shlib-undefined.s =================================================================== --- test/elf2/allow-shlib-undefined.s +++ test/elf2/allow-shlib-undefined.s @@ -0,0 +1,18 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/allow-shlib-undefined.s -o %t +# RUN: lld -shared -flavor gnu2 %t -o %t.so +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 + +# Executable: does not link by default and with +# --no-allow-shlib-undefined but links with --allow-shlib-undefined +# RUN: not lld -flavor gnu2 %t1 %t.so -o %t2 +# RUN: not lld -flavor gnu2 --no-allow-shlib-undefined %t1 %t.so -o %t2 +# RUN: lld -flavor gnu2 --allow-shlib-undefined %t1 %t.so -o %t2 + +# Shared library: links successfully by default and with +# --allow-shlib-undefined but does not link with --no-allow-shlib-undefined +# RUN: lld -shared --allow-shlib-undefined -flavor gnu2 %t -o %t.so +# RUN: not lld -shared --no-allow-shlib-undefined -flavor gnu2 %t -o %t.so + +.globl _start +_start: + call _shared