Index: lld/ELF/InputFiles.h =================================================================== --- lld/ELF/InputFiles.h +++ lld/ELF/InputFiles.h @@ -381,12 +381,14 @@ template void parse(); - // Used for --no-allow-shlib-undefined. - bool allNeededIsKnown; - // Used for --as-needed bool isNeeded; + // Non-weak undefined symbols which are not yet resolved when the SO is + // parsed. Only filled if we check unresolved symbols in shared libraries, + // i.e. (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore). + std::vector requiredSymbols; + private: template std::vector parseVerneed(const llvm::object::ELFFile &obj, Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -1567,6 +1567,9 @@ Symbol *s = symtab->addSymbol( Undefined{this, name, sym.getBinding(), sym.st_other, sym.getType()}); s->exportDynamic = true; + if (s->isUndefined() && !s->isWeak() && + config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) + requiredSymbols.push_back(s); continue; } Index: lld/ELF/Writer.cpp =================================================================== --- lld/ELF/Writer.cpp +++ lld/ELF/Writer.cpp @@ -2006,6 +2006,10 @@ in.iplt->addSymbols(); if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) { + auto diagnose = + config->unresolvedSymbolsInShlib == UnresolvedPolicy::ReportError + ? errorOrWarn + : warn; // Error on undefined symbols in a shared object, if all of its DT_NEEDED // entries are seen. These cases would otherwise lead to runtime errors // reported by the dynamic linker. @@ -2013,23 +2017,18 @@ // ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to // catch more cases. That is too much for us. Our approach resembles the one // used in ld.gold, achieves a good balance to be useful but not too smart. - for (SharedFile *file : sharedFiles) - file->allNeededIsKnown = + for (SharedFile *file : sharedFiles) { + bool allNeededIsKnown = llvm::all_of(file->dtNeeded, [&](StringRef needed) { return symtab->soNames.count(needed); }); - - for (Symbol *sym : symtab->symbols()) - if (sym->isUndefined() && !sym->isWeak()) - if (auto *f = dyn_cast_or_null(sym->file)) - if (f->allNeededIsKnown) { - auto diagnose = config->unresolvedSymbolsInShlib == - UnresolvedPolicy::ReportError - ? errorOrWarn - : warn; - diagnose(toString(f) + ": undefined reference to " + - toString(*sym) + " [--no-allow-shlib-undefined]"); - } + if (!allNeededIsKnown) + continue; + for (Symbol *sym : file->requiredSymbols) + if (sym->isUndefined() && !sym->isWeak()) + diagnose(toString(file) + ": undefined reference to " + + toString(*sym) + " [--no-allow-shlib-undefined]"); + } } { Index: lld/test/ELF/unresolved-in-dso.ll =================================================================== --- /dev/null +++ lld/test/ELF/unresolved-in-dso.ll @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: echo 'callq undef@PLT' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %ta.o +# RUN: echo '.globl _shared; _shared: callq undef@PLT' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %tb.o +# RUN: ld.lld %tb.o -o %tb.so -shared +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: not ld.lld --gc-sections %t.o %ta.o %tb.so -o /dev/null 2>&1 | \ +# RUN: FileCheck %s + +# CHECK: error: {{.*}}.so: undefined reference to undef [--no-allow-shlib-undefined] + +.globl _start +_start: