diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1144,30 +1144,28 @@ if (!orderFile.empty()) parseOrderFile(orderFile); - if (config->outputType == MH_EXECUTE && isa(config->entry)) { - error("undefined symbol: " + toString(*config->entry)); - return false; - } + if (config->entry) + if (auto *undefined = dyn_cast(config->entry)) + treatUndefinedSymbol(*undefined, "the entry point"); + // FIXME: This prints symbols that are undefined both in input files and // via -u flag twice. - for (const Symbol *undefined : config->explicitUndefineds) { - if (isa(undefined)) { - error("undefined symbol: " + toString(*undefined) + - "\n>>> referenced by flag -u " + toString(*undefined)); - return false; - } + for (const Symbol *sym : config->explicitUndefineds) { + if (const auto *undefined = dyn_cast(sym)) + treatUndefinedSymbol(*undefined, "-u"); } // Literal exported-symbol names must be defined, but glob // patterns need not match. for (const CachedHashStringRef &cachedName : config->exportedSymbols.literals) { if (const Symbol *sym = symtab->find(cachedName)) - if (isa(sym)) - continue; - error("undefined symbol: " + cachedName.val() + - "\n>>> referenced from option -exported_symbol(s_list)"); + if (const auto *undefined = dyn_cast(sym)) + treatUndefinedSymbol(*undefined, "-exported_symbol(s_list)"); } + // FIXME: should terminate the link early based on errors encountered so + // far? + createSyntheticSections(); createSyntheticSymbols(); diff --git a/lld/MachO/SymbolTable.h b/lld/MachO/SymbolTable.h --- a/lld/MachO/SymbolTable.h +++ b/lld/MachO/SymbolTable.h @@ -65,7 +65,7 @@ std::vector symVector; }; -void treatUndefinedSymbol(const Undefined &); +void treatUndefinedSymbol(const Undefined &, StringRef source = ""); extern SymbolTable *symtab; diff --git a/lld/MachO/SymbolTable.cpp b/lld/MachO/SymbolTable.cpp --- a/lld/MachO/SymbolTable.cpp +++ b/lld/MachO/SymbolTable.cpp @@ -186,20 +186,21 @@ return s; } -void lld::macho::treatUndefinedSymbol(const Undefined &sym) { - auto message = [](const Undefined &sym) { +void lld::macho::treatUndefinedSymbol(const Undefined &sym, StringRef source) { + auto message = [source, &sym]() { std::string message = "undefined symbol: " + toString(sym); - std::string fileName = toString(sym.getFile()); - if (!fileName.empty()) - message += "\n>>> referenced by " + fileName; + 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(sym)); + error(message()); break; case UndefinedSymbolTreatment::warning: - warn(message(sym)); + warn(message()); LLVM_FALLTHROUGH; case UndefinedSymbolTreatment::dynamic_lookup: case UndefinedSymbolTreatment::suppress: diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -1055,7 +1055,7 @@ } template void Writer::run() { - if (config->entry) + if (config->entry && !isa(config->entry)) prepareBranchTarget(config->entry); scanRelocations(); if (in.stubHelper->isNeeded()) diff --git a/lld/test/MachO/entry-symbol.s b/lld/test/MachO/entry-symbol.s --- a/lld/test/MachO/entry-symbol.s +++ b/lld/test/MachO/entry-symbol.s @@ -22,7 +22,11 @@ # CHECK-NEXT: entryoff [[#ENTRYOFF]] # RUN: %lld -lSystem -o %t/dysym-main %t/not-main.o %t/libfoo.dylib -e _dysym_main -# RUN: llvm-objdump --macho --all-headers --indirect-symbols --lazy-bind %t/dysym-main | FileCheck %s --check-prefix=DYSYM +# RUN: llvm-objdump --macho --all-headers --indirect-symbols --lazy-bind %t/dysym-main | FileCheck %s --check-prefix=DYSYM -DDYLIB=libfoo + +# RUN: %lld -lSystem -o %t/dyn-lookup %t/not-main.o -e _dysym_main -undefined dynamic_lookup +# RUN: llvm-objdump --macho --all-headers --indirect-symbols --lazy-bind %t/dyn-lookup | FileCheck %s --check-prefix=DYSYM -DDYLIB=flat-namespace + # DYSYM-LABEL: Indirect symbols for (__TEXT,__stubs) 1 entries # DYSYM-NEXT: address index name # DYSYM-NEXT: 0x[[#%x,DYSYM_ENTRY_ADDR:]] [[#]] _dysym_main @@ -30,8 +34,8 @@ # DYSYM-NEXT: cmdsize 24 # DYSYM-NEXT: entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]] # DYSYM-LABEL: Lazy bind table: -# DYSYM-NEXT: segment section address dylib symbol -# DYSYM-NEXT: __DATA __la_symbol_ptr {{.*}} libfoo _dysym_main +# DYSYM-NEXT: segment section address dylib symbol +# DYSYM-NEXT: __DATA __la_symbol_ptr {{.*}} [[DYLIB]] _dysym_main # RUN: %lld -lSystem -o %t/weak-dysym-main %t/not-main.o %t/libfoo.dylib -e _weak_dysym_main # RUN: llvm-objdump --macho --all-headers --indirect-symbols --bind --weak-bind %t/weak-dysym-main | FileCheck %s --check-prefix=WEAK-DYSYM @@ -42,8 +46,8 @@ # WEAK-DYSYM-NEXT: cmdsize 24 # WEAK-DYSYM-NEXT: entryoff [[#%u, DYSYM_ENTRY_ADDR - 0x100000000]] # WEAK-DYSYM-LABEL: Bind table: -# WEAK-DYSYM-NEXT: segment section address type addend dylib symbol -# WEAK-DYSYM: __DATA __la_symbol_ptr {{.*}} pointer 0 libfoo _weak_dysym_main +# WEAK-DYSYM-NEXT: segment section address type addend dylib symbol +# WEAK-DYSYM: __DATA __la_symbol_ptr {{.*}} pointer 0 libfoo _weak_dysym_main # WEAK-DYSYM-LABEL: Weak bind table: # WEAK-DYSYM-NEXT: segment section address type addend symbol # WEAK-DYSYM-NEXT: __DATA __la_symbol_ptr {{.*}} pointer 0 _weak_dysym_main @@ -55,7 +59,8 @@ # RUN: not %lld -o /dev/null %t/not-main.o -e _missing 2>&1 | FileCheck %s --check-prefix=UNDEFINED # UNDEFINED: error: undefined symbol: _missing # RUN: not %lld -o /dev/null %t/not-main.o 2>&1 | FileCheck %s --check-prefix=DEFAULT-ENTRY -# DEFAULT-ENTRY: error: undefined symbol: _main +# DEFAULT-ENTRY: error: undefined symbol: _main +# DEFAULT-ENTRY-NEXT: >>> referenced by the entry point #--- libfoo.s .text diff --git a/lld/test/MachO/export-options.s b/lld/test/MachO/export-options.s --- a/lld/test/MachO/export-options.s +++ b/lld/test/MachO/export-options.s @@ -21,9 +21,15 @@ # RUN: FileCheck --check-prefix=UNDEF %s # UNDEF: error: undefined symbol: absent_literal -# UNDEF-NEXT: >>> referenced from option -exported_symbol(s_list) +# UNDEF-NEXT: >>> referenced by -exported_symbol(s_list) # UNDEF-NOT: error: {{.*}} absent_gl{{.}}b +## Check that dynamic_lookup suppresses the error +# RUN: %lld -dylib %t/default.o -undefined dynamic_lookup -o %t/dyn-lookup \ +# RUN: -exported_symbol absent_literal +# RUN: llvm-objdump --macho --syms %t/dyn-lookup | FileCheck %s --check-prefix=DYN +# DYN: *UND* absent_literal + ## Check that exported literal symbols are present in output's ## symbol table, even lazy symbols which would otherwise be omitted # RUN: %lld -dylib %t/default.o %t/lazydef.a -o %t/lazydef \ diff --git a/lld/test/MachO/u.s b/lld/test/MachO/u.s --- a/lld/test/MachO/u.s +++ b/lld/test/MachO/u.s @@ -6,18 +6,25 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/main.o %t/main.s -# RUN: %lld %t/main.o %t/lib.a -o /dev/null -why_load | \ +# RUN: %lld -lSystem %t/main.o %t/lib.a -o /dev/null -why_load | \ # RUN: FileCheck %s --check-prefix=NOFOO --allow-empty -# RUN: %lld %t/main.o %t/lib.a -u _foo -o /dev/null -why_load | \ +# RUN: %lld -lSystem %t/main.o %t/lib.a -u _foo -o /dev/null -why_load | \ # RUN: FileCheck %s --check-prefix=FOO -# RUN: not %lld %t/main.o %t/lib.a -u _asdf -o /dev/null 2>&1 | \ +# RUN: not %lld %t/main.o %t/lib.a -u _asdf -u _fdsa -o /dev/null 2>&1 | \ # RUN: FileCheck %s --check-prefix=UNDEF +# RUN: %lld -lSystem %t/main.o %t/lib.a -u _asdf -undefined dynamic_lookup -o %t/dyn-lookup +# RUN: llvm-objdump --macho --syms %t/dyn-lookup | FileCheck %s --check-prefix=DYN + # NOFOO-NOT: _foo forced load of {{.+}}lib.a(foo.o) # FOO: _foo forced load of {{.+}}lib.a(foo.o) -# UNDEF: error: undefined symbol: _asdf +# UNDEF: error: undefined symbol: _asdf +# UNDEF-NEXT: >>> referenced by -u +# UNDEF: error: undefined symbol: _fdsa +# UNDEF-NEXT: >>> referenced by -u +# DYN: *UND* _asdf #--- foo.s .globl _foo