diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -30,6 +30,14 @@ llvm::VersionTuple sdk; }; +enum class UndefinedSymbolTreatment { + unknown, + error, + warning, + suppress, + dynamic_lookup, +}; + struct Configuration { Symbol *entry; bool hasReexports = false; @@ -52,6 +60,8 @@ bool demangle = false; llvm::MachO::Architecture arch; PlatformInfo platform; + UndefinedSymbolTreatment undefinedSymbolTreatment = + UndefinedSymbolTreatment::error; llvm::MachO::HeaderFileType outputType; std::vector systemLibraryRoots; std::vector librarySearchPaths; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -599,6 +599,22 @@ error(Twine("malformed sdk version: ") + sdkVersionStr); } +static void handleUndefined(const opt::Arg *arg) { + StringRef treatmentStr = arg->getValue(0); + config->undefinedSymbolTreatment = + llvm::StringSwitch(treatmentStr) + .Case("error", UndefinedSymbolTreatment::error) + .Case("warning", UndefinedSymbolTreatment::warning) + .Case("suppress", UndefinedSymbolTreatment::suppress) + .Case("dynamic_lookup", UndefinedSymbolTreatment::dynamic_lookup) + .Default(UndefinedSymbolTreatment::unknown); + if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::unknown) { + warn(Twine("unknown -undefined TREATMENT '") + treatmentStr + + "', defaulting to 'error'"); + config->undefinedSymbolTreatment = UndefinedSymbolTreatment::error; + } +} + static void warnIfDeprecatedOption(const opt::Option &opt) { if (!opt.getGroup().isValid()) return; @@ -809,6 +825,9 @@ case OPT_platform_version: handlePlatformVersion(arg); break; + case OPT_undefined: + handleUndefined(arg); + break; default: break; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -435,7 +435,6 @@ def undefined : Separate<["-"], "undefined">, MetaVarName<"">, HelpText<"Handle undefined symbols according to : error, warning, suppress, or dynamic_lookup (default is error)">, - Flags<[HelpHidden]>, Group; def rpath : Separate<["-"], "rpath">, MetaVarName<"">, diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -55,6 +55,8 @@ std::vector symVector; }; +extern void treatUndefinedSymbol(StringRef symbolName, StringRef fileName); + extern SymbolTable *symtab; } // namespace macho diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SymbolTable.h" +#include "Config.h" #include "InputFiles.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" @@ -154,4 +155,26 @@ return s; } +void lld::macho::treatUndefinedSymbol(StringRef symbolName, + StringRef fileName) { + std::string message = ("undefined symbol: " + symbolName).str(); + if (!fileName.empty()) + message += ("\n>>> referenced by " + fileName).str(); + switch (config->undefinedSymbolTreatment) { + case UndefinedSymbolTreatment::suppress: + break; + case UndefinedSymbolTreatment::error: + error(message); + break; + case UndefinedSymbolTreatment::warning: + warn(message); + break; + case UndefinedSymbolTreatment::dynamic_lookup: + error("dynamic_lookup unimplemented for " + message); + break; + case UndefinedSymbolTreatment::unknown: + llvm_unreachable("unknown -undefined TREATMENT"); + } +} + SymbolTable *macho::symtab; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -412,8 +412,7 @@ for (Reloc &r : isec->relocs) { if (auto *s = r.referent.dyn_cast()) { if (isa(s)) - error("undefined symbol " + toString(*s) + ", referenced from " + - toString(isec->file)); + treatUndefinedSymbol(toString(*s), toString(isec->file)); else target->prepareSymbolRelocation(s, isec, r); } else { diff --git a/lld/test/MachO/demangle.s b/lld/test/MachO/demangle.s --- a/lld/test/MachO/demangle.s +++ b/lld/test/MachO/demangle.s @@ -6,8 +6,8 @@ # RUN: not %lld -demangle %t.o -o /dev/null 2>&1 | \ # RUN: FileCheck --check-prefix=DEMANGLE %s -# CHECK: undefined symbol __Z1fv -# DEMANGLE: undefined symbol f() +# CHECK: undefined symbol: __Z1fv +# DEMANGLE: undefined symbol: f() .globl _main _main: diff --git a/lld/test/MachO/invalid/stub-link.s b/lld/test/MachO/invalid/stub-link.s --- a/lld/test/MachO/invalid/stub-link.s +++ b/lld/test/MachO/invalid/stub-link.s @@ -8,8 +8,8 @@ # RUN: llvm-mc -filetype obj -triple x86_64-apple-ios %s -o %t/test.o # RUN: not lld -flavor darwinnew -o %t/test -syslibroot %S/../Inputs/iPhoneSimulator.sdk -lSystem %t/test.o 2>&1 | FileCheck %s -# CHECK-DAG: error: undefined symbol __cache_handle_memory_pressure_event -# CHECK-DAG: error: undefined symbol _from_non_reexported_tapi_dylib +# CHECK-DAG: error: undefined symbol: __cache_handle_memory_pressure_event +# CHECK-DAG: error: undefined symbol: _from_non_reexported_tapi_dylib .section __TEXT,__text .global _main diff --git a/lld/test/MachO/invalid/undefined-symbol.s b/lld/test/MachO/invalid/undefined-symbol.s --- a/lld/test/MachO/invalid/undefined-symbol.s +++ b/lld/test/MachO/invalid/undefined-symbol.s @@ -10,7 +10,8 @@ # RUN: FileCheck %s -DSYM=_bar -DFILENAME='foo.a(foo.o)' # RUN: not %lld -o /dev/null %t/main.o -force_load %t/foo.a 2>&1 | \ # RUN: FileCheck %s -DSYM=_bar -DFILENAME='foo.a(foo.o)' -# CHECK: error: undefined symbol [[SYM]], referenced from [[FILENAME]] +# CHECK: error: undefined symbol: [[SYM]] +# CHECK-NEXT: >>> referenced by [[FILENAME]] #--- foo.s .globl _foo diff --git a/lld/test/MachO/treat-undef-sym.s b/lld/test/MachO/treat-undef-sym.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/treat-undef-sym.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %s -o %t.o +# RUN: not %lld -undefined bogus -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=UNKNOWN +# RUN: not %lld -undefined error -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=ERROR +# RUN: %no_fatal_warnings_lld -undefined warning -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=WARNING +# RUN: %lld -undefined suppress -o /dev/null %t.o 2>&1 | \ +# RUN: FileCheck %s -check-prefix=SUPPRESS --allow-empty + +# ERROR: error: undefined symbol: _bar +# ERROR-NEXT: >>> referenced by + +# WARNING: warning: undefined symbol: _bar +# WARNING-NEXT: >>> referenced by + +# SUPPRESS-NOT: undefined symbol: _bar + +# UNKNOWN: unknown -undefined TREATMENT 'bogus' +# UNKNOWN-NEXT: error: undefined symbol: _bar +# UNKNOWN-NEXT: >>> referenced by + +.globl _main +_main: + callq _bar + ret diff --git a/lld/test/MachO/weak-reference.s b/lld/test/MachO/weak-reference.s --- a/lld/test/MachO/weak-reference.s +++ b/lld/test/MachO/weak-reference.s @@ -94,7 +94,7 @@ ## Weak references must still be satisfied at link time. # RUN: not %lld -lSystem %t/invalid.o -o /dev/null 2>&1 | FileCheck %s \ # RUN: --check-prefix=INVALID -DDIR=%t -# INVALID: error: undefined symbol _missing, referenced from [[DIR]]/invalid.o +# INVALID: error: undefined symbol: _missing #--- libfoo.s .globl _foo, _foo_fn, _weak_foo, _weak_foo_fn