diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -69,7 +69,9 @@ std::vector symVector; }; -void treatUndefinedSymbol(const Undefined &, StringRef source = ""); +void treatUndefinedSymbol(const Undefined &, StringRef source); +void treatUndefinedSymbol(const Undefined &, const InputSection *, + uint64_t offset); extern std::unique_ptr symtab; diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -302,50 +302,78 @@ seg->segmentEndSymbols.push_back(createBoundarySymbol(sym)); } -void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { +// Try to find a definition for an undefined symbol. +// Returns true if a definition was found and no diagnostics are needed. +static bool recoverFromUndefinedSymbol(const Undefined &sym) { // Handle start/end symbols. StringRef name = sym.getName(); - if (name.consume_front("section$start$")) - return handleSectionBoundarySymbol(sym, name, Boundary::Start); - if (name.consume_front("section$end$")) - return handleSectionBoundarySymbol(sym, name, Boundary::End); - if (name.consume_front("segment$start$")) - return handleSegmentBoundarySymbol(sym, name, Boundary::Start); - if (name.consume_front("segment$end$")) - return handleSegmentBoundarySymbol(sym, name, Boundary::End); + if (name.consume_front("section$start$")) { + handleSectionBoundarySymbol(sym, name, Boundary::Start); + return true; + } + if (name.consume_front("section$end$")) { + handleSectionBoundarySymbol(sym, name, Boundary::End); + return true; + } + if (name.consume_front("segment$start$")) { + handleSegmentBoundarySymbol(sym, name, Boundary::Start); + return true; + } + if (name.consume_front("segment$end$")) { + handleSegmentBoundarySymbol(sym, name, Boundary::End); + return true; + } // Handle -U. if (config->explicitDynamicLookups.count(sym.getName())) { symtab->addDynamicLookup(sym.getName()); - return; + return true; } // Handle -undefined. - auto message = [source, &sym]() { - std::string message = "undefined symbol"; - if (config->archMultiple) - message += (" for arch " + getArchitectureName(config->arch())).str(); - message += ": " + toString(sym); - if (!source.empty()) - message += "\n>>> referenced by " + source.str(); - else - message += "\n>>> referenced by " + toString(sym.getFile()); - return message; - }; - switch (config->undefinedSymbolTreatment) { - case UndefinedSymbolTreatment::error: - error(message()); - break; - case UndefinedSymbolTreatment::warning: - warn(message()); - LLVM_FALLTHROUGH; - case UndefinedSymbolTreatment::dynamic_lookup: - case UndefinedSymbolTreatment::suppress: + if (config->undefinedSymbolTreatment == + UndefinedSymbolTreatment::dynamic_lookup || + config->undefinedSymbolTreatment == UndefinedSymbolTreatment::suppress) { symtab->addDynamicLookup(sym.getName()); - break; - case UndefinedSymbolTreatment::unknown: - llvm_unreachable("unknown -undefined TREATMENT"); + return true; } + + // We do not return true here, as we still need to print diagnostics. + if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::warning) + symtab->addDynamicLookup(sym.getName()); + + return false; +} + +static void printUndefinedDiagnostic(StringRef name, StringRef source) { + std::string message = "undefined symbol"; + if (config->archMultiple) + message += (" for arch " + getArchitectureName(config->arch())).str(); + message += (": " + name + "\n>>> referenced by " + source).str(); + + if (config->undefinedSymbolTreatment == UndefinedSymbolTreatment::error) + error(message); + else if (config->undefinedSymbolTreatment == + UndefinedSymbolTreatment::warning) + warn(message); + else + assert(false && "diagnostics make sense for -undefined error|warning only"); +} + +void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { + if (recoverFromUndefinedSymbol(sym)) + return; + printUndefinedDiagnostic(sym.getName(), source); +} + +void lld::macho::treatUndefinedSymbol(const Undefined &sym, + const InputSection *isec, + uint64_t offset) { + if (recoverFromUndefinedSymbol(sym)) + return; + + // TODO: Get source file/line from debug information. + printUndefinedDiagnostic(toString(sym), isec->getLocation(offset)); } std::unique_ptr macho::symtab; diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -273,7 +273,7 @@ r.referent = s = sym; } if (auto *undefined = dyn_cast(s)) { - treatUndefinedSymbol(*undefined); + treatUndefinedSymbol(*undefined, isec, r.offset); // treatUndefinedSymbol() can replace s with a DylibSymbol; re-check. if (isa(s)) continue; diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -659,7 +659,7 @@ } if (auto *sym = r.referent.dyn_cast()) { if (auto *undefined = dyn_cast(sym)) - treatUndefinedSymbol(*undefined); + treatUndefinedSymbol(*undefined, isec, r.offset); // treatUndefinedSymbol() can replace sym with a DylibSymbol; re-check. if (!isa(sym) && validateSymbolRelocation(sym, isec, r)) prepareSymbolRelocation(sym, isec, r); 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 @@ -4,13 +4,13 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o # RUN: llvm-ar crs %t/foo.a %t/foo.o # RUN: not %lld --icf=all -o /dev/null %t/main.o 2>&1 | \ -# RUN: FileCheck %s -DSYM=_foo -DFILENAME=%t/main.o +# RUN: FileCheck %s -DSYM=_foo -DLOC='%t/main.o:(symbol _main+0x1)' # RUN: not %lld -o /dev/null %t/main.o %t/foo.a 2>&1 | \ -# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)' +# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)' # RUN: not %lld -o /dev/null %t/main.o -force_load %t/foo.a 2>&1 | \ -# RUN: FileCheck %s -DSYM=_bar -DFILENAME='%t/foo.a(foo.o)' +# RUN: FileCheck %s -DSYM=_bar -DLOC='%t/foo.a(foo.o):(symbol _foo+0x1)' # CHECK: error: undefined symbol: [[SYM]] -# CHECK-NEXT: >>> referenced by [[FILENAME]] +# CHECK-NEXT: >>> referenced by [[LOC]] #--- foo.s .globl _foo