Index: include/lld/Core/LinkingContext.h =================================================================== --- include/lld/Core/LinkingContext.h +++ include/lld/Core/LinkingContext.h @@ -149,6 +149,12 @@ /// to be an error. bool allowShlibUndefines() const { return _allowShlibUndefines; } + /// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a + /// SharedLibraryAtom for the link to be successful. This method controls + /// whether core linking considers remaining undefines from the shared library + /// and executable to be an error. + StringRef unresolvedSymbols() { return _unresolvedSymbols; } + /// If true, core linking will write the path to each input file to stdout /// (i.e. llvm::outs()) as it is used. This is used to implement the -t /// linker option. @@ -197,6 +203,7 @@ _allowRemainingUndefines = allow; } void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; } + void setUnresolvedSymbols(StringRef value) { _unresolvedSymbols = value; } void setLogInputFiles(bool log) { _logInputFiles = log; } // Returns true if multiple definitions should not be treated as a @@ -340,6 +347,7 @@ bool _allowRemainingUndefines; bool _logInputFiles; bool _allowShlibUndefines; + StringRef _unresolvedSymbols; OutputFileType _outputFileType; std::vector _deadStripRoots; std::map _aliasSymbols; Index: lib/Core/LinkingContext.cpp =================================================================== --- lib/Core/LinkingContext.cpp +++ lib/Core/LinkingContext.cpp @@ -25,7 +25,8 @@ _warnIfCoalesableAtomsHaveDifferentLoadName(false), _printRemainingUndefines(true), _allowRemainingUndefines(false), _logInputFiles(false), _allowShlibUndefines(true), - _outputFileType(OutputFileType::Default), _nextOrdinal(0) {} + _unresolvedSymbols(""), _outputFileType(OutputFileType::Default), + _nextOrdinal(0) {} LinkingContext::~LinkingContext() {} Index: lib/Core/Resolver.cpp =================================================================== --- lib/Core/Resolver.cpp +++ lib/Core/Resolver.cpp @@ -452,6 +452,23 @@ if (undef->canBeNull() != UndefinedAtom::canBeNullNever) continue; + // skip over the undefined symbols for executable + if (!_ctx.unresolvedSymbols().compare("ignore-all")) + if (!isa(undef->file())) + continue; + + // if the unresolved symbol is from shared library skip over it + // But if it is from a regular object file then report it + if (!_ctx.unresolvedSymbols().compare("ignore-in-shared-libs")) + if (isa(undef->file()) && _ctx.allowShlibUndefines()) + continue; + + // if the unresolved symbol is from shared library report it + // But if it is from a regular object file then skip over it + if (!_ctx.unresolvedSymbols().compare("ignore-in-object-files")) + if (!isa(undef->file())) + continue; + // If this is a library and undefined symbols are allowed on the // target platform, skip over it. if (isa(undef->file()) && _ctx.allowShlibUndefines()) Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -426,6 +426,38 @@ ctx->setAllowRemainingUndefines(true); } + // Handle --unresolved-symbols option + if (auto *arg = parsedArgs.getLastArg(OPT_unresolved_symbols)) { + StringRef val = arg->getValue(); + if (val.empty()) { + diag << "error: option --unresolved-symbols=" + " must take one of the following arguments:\n" + "\tignore-all, report-all, " + "ignore-in-shared-libs, ignore-in-object-files\n"; + return false; + } + else if (val.compare("ignore-all") && + val.compare("report-all") && + val.compare("ignore-in-object-files") && + val.compare("ignore-in-shared-libs")) { + + diag << "error: option --unresolved-symbols=" + << val + << " must take one of the following arguments:\n" + "\tignore-all, report-all, " + "ignore-in-shared-libs, ignore-in-object-files\n"; + return false; + } + + if (!val.compare("report-all") || + !val.compare("ignore-in-object-files")) + ctx->setAllowShlibUndefines(false); + + ctx->setUnresolvedSymbols(arg->getValue()); + ctx->setPrintRemainingUndefines(true); + ctx->setAllowRemainingUndefines(false); + } + // Handle --stats. if (parsedArgs.hasArg(OPT_stats)) { ctx->setCollectStats(true); Index: lib/Driver/GnuLdOptions.td =================================================================== --- lib/Driver/GnuLdOptions.td +++ lib/Driver/GnuLdOptions.td @@ -220,6 +220,11 @@ def allow_multiple_definition: Flag<["--"], "allow-multiple-definition">, HelpText<"Allow multiple definitions">, Group; +def unresolved_symbols: Joined<["--"], "unresolved-symbols=">, + HelpText<"control reporting unresolved symbols">, + Group; +def unresolved_symbols_alias : Joined<["--"], "unresolved-symbols">, + Alias; defm defsym : mDashEq<"defsym", "Create a global symbol in the output file " "containing the absolute address given by expression">, Index: test/elf/Inputs/foo_unresolved-symbols.c =================================================================== --- test/elf/Inputs/foo_unresolved-symbols.c +++ test/elf/Inputs/foo_unresolved-symbols.c @@ -0,0 +1,7 @@ + + +extern int bar(); +int foo() { + bar(); + return 0; +} Index: test/elf/Inputs/main_unresolved-symbols.c =================================================================== --- test/elf/Inputs/main_unresolved-symbols.c +++ test/elf/Inputs/main_unresolved-symbols.c @@ -0,0 +1,13 @@ +#include + +extern int foo(); +extern int goo(); + +extern int car(); + +int main() { + goo(); + car(); + printf("main\n"); + return 0; +} Index: test/elf/unresolved-symbols.test =================================================================== --- test/elf/unresolved-symbols.test +++ test/elf/unresolved-symbols.test @@ -0,0 +1,129 @@ +# +# This test creates a executable and tests the options that are used to +# to create an executable and a shared library +# +# This test will fail because there are unresolved symbols from the shared +# library and we are passing --no-allow-shlib-undefined +# Test if option is used in correct form +RUN: clang -c %p/Inputs/main_unresolved-symbols.c -o %p/Inputs/main_unresolved-symbols.o +RUN: clang -c %p/Inputs/foo_unresolved-symbols.c -o %p/Inputs/foo_unresolved-symbols.o +RUN: lld -flavor gnu -shared %p/Inputs/foo_unresolved-symbols.o -o %p/Inputs/libfoo_unresolved-symbols.so + +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -o %t --unresolved-symbols 2> %t4 +RUN: FileCheck -check-prefix=ERROR %s < %t4 +RUN: FileCheck -check-prefix=OPTIONS %s < %t4 + +# Test if option is used in correct form +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -o %t --unresolved-symbols= 2> %t4 +RUN: FileCheck -check-prefix=ERROR %s < %t4 +RUN: FileCheck -check-prefix=OPTIONS %s < %t4 + +# Test if option value used is correct +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -o %t --unresolved-symbols=abcd 2> %t4 +RUN: FileCheck -check-prefix=ERROR1 %s < %t4 +RUN: FileCheck -check-prefix=OPTIONS %s < %t4 + +# Test behaviour of --unresolved-symbols=report-all +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=report-all 2> %t1 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t1 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t1 + +# Test behaviour of --unresolved-symbols=ignore-all +RUN: lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-all 2> %t2 + +# Test behaviour of --unresolved-symbols=ignore-in-object-files +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-in-object-files 2> %t2 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t2 + +# Test behaviour of --unresolved-symbols=ignore-in-shared-libs +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-in-shared-libs 2> %t3 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t3 + +# Test behaviour of --unresolved-symbols=report-all +# along with --allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=report-all \ +RUN: --allow-shlib-undefined 2> %t1 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t1 + +# Test behaviour of --unresolved-symbols=ignore-all +# along with --allow-shlib-undefined +RUN: lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-all \ +RUN: --allow-shlib-undefined 2> %t2 + +# Test behaviour of --unresolved-symbols=ignore-in-object-files +# along with --allow-shlib-undefined +RUN: lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-in-object-files \ +RUN: --allow-shlib-undefined 2> %t2 + +# Test behaviour of --unresolved-symbols=ignore-in-shared-libs +# along with --allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-in-shared-libs \ +RUN: --allow-shlib-undefined 2> %t3 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t3 + +# Test behaviour of --unresolved-symbols=report-all +# along with --no-allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=report-all \ +RUN: --no-allow-shlib-undefined 2> %t1 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t1 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t1 + +# Test behaviour of --unresolved-symbols=ignore-all +# along with --no-allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-all \ +RUN: --no-allow-shlib-undefined 2> %t1 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t1 + +# Test behaviour of --unresolved-symbols=ignore-in-object-files +# along with --no-allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main %p/Inputs/libfoo_unresolved-symbols.so -o %t \ +RUN: --unresolved-symbols=ignore-in-object-files --no-allow-shlib-undefined 2> %t2 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t2 + +# Test behaviour of --unresolved-symbols=ignore-in-shared-libs +# along with --no-allow-shlib-undefined +RUN: not lld -flavor gnu %p/Inputs/main_unresolved-symbols.o -e main \ +RUN: %p/Inputs/libfoo_unresolved-symbols.so -o %t --unresolved-symbols=ignore-in-shared-libs \ +RUN: --no-allow-shlib-undefined 2> %t3 +RUN: FileCheck -check-prefix=UNDEFINED-EXEC %s < %t3 +RUN: FileCheck -check-prefix=UNDEFINED-SHLIB %s < %t3 + +# Test behaviour of --unresolved-symbols=report-all +# along with -shared +RUN: not lld -flavor gnu -shared -fpic %p/Inputs/foo_unresolved-symbols.o -o %t \ +RUN: --unresolved-symbols=report-all 2> %t3 +RUN: FileCheck -check-prefix=UNDEFINED-OBJ %s < %t3 + +# Test behaviour of --unresolved-symbols=ignore-all +# along with -shared +RUN: lld -flavor gnu -shared -fpic %p/Inputs/foo_unresolved-symbols.o -o %t \ +RUN: --unresolved-symbols=ignore-all 2> %t3 + +# Test behaviour of --unresolved-symbols=ignore-in-object-files +# along with -shared +RUN: lld -flavor gnu -shared -fpic %p/Inputs/foo_unresolved-symbols.o -o %t \ +RUN: --unresolved-symbols=ignore-in-object-files 2> %t3 + +# Test behaviour of --unresolved-symbols=ignore-in-shared-libs +# along with -shared +RUN: not lld -flavor gnu -shared -fpic %p/Inputs/foo_unresolved-symbols.o -o %t \ +RUN: --unresolved-symbols=ignore-in-shared-libs 2> %t3 +RUN: FileCheck -check-prefix=UNDEFINED-OBJ %s < %t3 + +ERROR: error: option --unresolved-symbols= must take one of the following arguments: +ERROR1: error: option --unresolved-symbols=abcd must take one of the following arguments: +OPTIONS: ignore-all, report-all, ignore-in-shared-libs, ignore-in-object-files +UNDEFINED-SHLIB: Undefined symbol: {{.+[\\/]}}libfoo_unresolved-symbols.so: bar +UNDEFINED-OBJ: Undefined symbol: {{.+[\\/]}}foo_unresolved-symbols.o: bar +UNDEFINED-EXEC: Undefined symbol: {{.+[\\/]}}main_unresolved-symbols.o: goo +