Index: lld/trunk/include/lld/Core/Resolver.h =================================================================== --- lld/trunk/include/lld/Core/Resolver.h +++ lld/trunk/include/lld/Core/Resolver.h @@ -33,7 +33,7 @@ // InputFiles::Handler methods void doDefinedAtom(const DefinedAtom&); - void doUndefinedAtom(const UndefinedAtom&); + bool doUndefinedAtom(const UndefinedAtom &); void doSharedLibraryAtom(const SharedLibraryAtom &); void doAbsoluteAtom(const AbsoluteAtom &); Index: lld/trunk/include/lld/Core/SymbolTable.h =================================================================== --- lld/trunk/include/lld/Core/SymbolTable.h +++ lld/trunk/include/lld/Core/SymbolTable.h @@ -39,16 +39,16 @@ explicit SymbolTable(const LinkingContext &); /// @brief add atom to symbol table - void add(const DefinedAtom &); + bool add(const DefinedAtom &); /// @brief add atom to symbol table - void add(const UndefinedAtom &); + bool add(const UndefinedAtom &); /// @brief add atom to symbol table - void add(const SharedLibraryAtom &); + bool add(const SharedLibraryAtom &); /// @brief add atom to symbol table - void add(const AbsoluteAtom &); + bool add(const AbsoluteAtom &); /// @brief checks if name is in symbol table and if so atom is not /// UndefinedAtom @@ -102,8 +102,8 @@ }; typedef llvm::DenseSet AtomContentSet; - void addByName(const Atom &); - void addByContent(const DefinedAtom &); + bool addByName(const Atom &); + bool addByContent(const DefinedAtom &); const LinkingContext &_context; AtomToAtom _replacedAtoms; Index: lld/trunk/include/lld/Driver/GnuLdInputGraph.h =================================================================== --- lld/trunk/include/lld/Driver/GnuLdInputGraph.h +++ lld/trunk/include/lld/Driver/GnuLdInputGraph.h @@ -80,8 +80,9 @@ /// to start processing files as part of the input element from beginning. /// Reset the next file index to 0 only if the node is an archive library. void resetNextIndex() override { - if (_files[0]->kind() == File::kindArchiveLibrary && - !_attributes._isWholeArchive) { + auto kind = _files[0]->kind(); + if (kind == File::kindSharedLibrary || + (kind == File::kindArchiveLibrary && !_attributes._isWholeArchive)) { _nextFileIndex = 0; } } Index: lld/trunk/lib/Core/Resolver.cpp =================================================================== --- lld/trunk/lib/Core/Resolver.cpp +++ lld/trunk/lib/Core/Resolver.cpp @@ -48,15 +48,12 @@ } // namespace void Resolver::handleFile(const File &file) { - bool isEmpty = file.defined().empty() && file.undefined().empty() && - file.sharedLibrary().empty() && file.absolute().empty(); - if (isEmpty) - return; - + bool undefAdded = false; for (const DefinedAtom *atom : file.defined()) doDefinedAtom(*atom); for (const UndefinedAtom *atom : file.undefined()) - doUndefinedAtom(*atom); + if (doUndefinedAtom(*atom)) + undefAdded = true; for (const SharedLibraryAtom *atom : file.sharedLibrary()) doSharedLibraryAtom(*atom); for (const AbsoluteAtom *atom : file.absolute()) @@ -65,7 +62,9 @@ // Notify the input file manager of the fact that we have made some progress // on linking using the current input file. It may want to know the fact for // --start-group/--end-group. - _context.getInputGraph().notifyProgress(); + if (undefAdded) { + _context.getInputGraph().notifyProgress(); + } } void Resolver::forEachUndefines(bool searchForOverrides, @@ -124,7 +123,7 @@ }); } -void Resolver::doUndefinedAtom(const UndefinedAtom &atom) { +bool Resolver::doUndefinedAtom(const UndefinedAtom &atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " UndefinedAtom: " << llvm::format("0x%09lX", &atom) @@ -134,7 +133,7 @@ _atoms.push_back(&atom); // tell symbol table - _symbolTable.add(atom); + bool newUndefAdded = _symbolTable.add(atom); // If the undefined symbol has an alternative name, try to resolve the // symbol with the name to give it a second chance. This feature is used @@ -145,6 +144,7 @@ _symbolTable.addReplacement(&atom, fallbackAtom); } } + return newUndefAdded; } /// \brief Add the section group and the group-child reference members. @@ -178,7 +178,8 @@ return true; } -// called on each atom when a file is added +// Called on each atom when a file is added. Returns true if a given +// atom is added to the symbol table. void Resolver::doDefinedAtom(const DefinedAtom &atom) { DEBUG_WITH_TYPE("resolver", llvm::dbgs() << " DefinedAtom: " Index: lld/trunk/lib/Core/SymbolTable.cpp =================================================================== --- lld/trunk/lib/Core/SymbolTable.cpp +++ lld/trunk/lib/Core/SymbolTable.cpp @@ -32,26 +32,26 @@ namespace lld { SymbolTable::SymbolTable(const LinkingContext &context) : _context(context) {} -void SymbolTable::add(const UndefinedAtom &atom) { addByName(atom); } +bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); } -void SymbolTable::add(const SharedLibraryAtom &atom) { addByName(atom); } +bool SymbolTable::add(const SharedLibraryAtom &atom) { return addByName(atom); } -void SymbolTable::add(const AbsoluteAtom &atom) { addByName(atom); } +bool SymbolTable::add(const AbsoluteAtom &atom) { return addByName(atom); } -void SymbolTable::add(const DefinedAtom &atom) { +bool SymbolTable::add(const DefinedAtom &atom) { if (!atom.name().empty() && atom.scope() != DefinedAtom::scopeTranslationUnit) { // Named atoms cannot be merged by content. assert(atom.merge() != DefinedAtom::mergeByContent); // Track named atoms that are not scoped to file (static). - addByName(atom); - return; + return addByName(atom); } if (atom.merge() == DefinedAtom::mergeByContent) { // Named atoms cannot be merged by content. assert(atom.name().empty()); - addByContent(atom); + return addByContent(atom); } + return false; } const Atom *SymbolTable::findGroup(StringRef sym) { @@ -162,16 +162,20 @@ + getSizeFollowReferences(atom, lld::Reference::kindLayoutAfter); } -void SymbolTable::addByName(const Atom &newAtom) { +bool SymbolTable::addByName(const Atom &newAtom) { StringRef name = newAtom.name(); assert(!name.empty()); const Atom *existing = findByName(name); if (existing == nullptr) { // Name is not in symbol table yet, add it associate with this atom. _nameTable[name] = &newAtom; - return; + return true; } + // Do nothing if the same object is added more than once. + if (existing == &newAtom) + return false; + // Name is already in symbol table and associated with another atom. bool useNew = true; switch (collide(existing->definition(), newAtom.definition())) { @@ -301,6 +305,7 @@ // New atom is not being used. Add it to replacement table. _replacedAtoms[&newAtom] = existing; } + return false; } unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) { @@ -332,17 +337,18 @@ return memcmp(lc.data(), rc.data(), lc.size()) == 0; } -void SymbolTable::addByContent(const DefinedAtom & newAtom) { +bool SymbolTable::addByContent(const DefinedAtom &newAtom) { // Currently only read-only constants can be merged. assert(newAtom.permissions() == DefinedAtom::permR__); AtomContentSet::iterator pos = _contentTable.find(&newAtom); if (pos == _contentTable.end()) { _contentTable.insert(&newAtom); - return; + return true; } const Atom* existing = *pos; // New atom is not being used. Add it to replacement table. _replacedAtoms[&newAtom] = existing; + return false; } const Atom *SymbolTable::findByName(StringRef sym) { Index: lld/trunk/test/elf/X86_64/Inputs/group/group.sh =================================================================== --- lld/trunk/test/elf/X86_64/Inputs/group/group.sh +++ lld/trunk/test/elf/X86_64/Inputs/group/group.sh @@ -31,6 +31,7 @@ gcc -c 1.c fn.c fn2.c fn1.c ar cr libfn.a fn.o fn2.o ar cr libfn1.a fn1.o +lld -flavor gnu -target x86_64 -shared -o libfn2.so fn2.o lld -flavor gnu -target x86_64 1.o libfn.a libfn1.a -o x lld -flavor gnu -target x86_64 1.o --start-group libfn.a libfn1.a --end-group -o x lld -flavor gnu -target x86_64 1.o --start-group fn.o fn2.o fn1.o --end-group -o x Index: lld/trunk/test/elf/X86_64/startGroupEndGroup.test =================================================================== --- lld/trunk/test/elf/X86_64/startGroupEndGroup.test +++ lld/trunk/test/elf/X86_64/startGroupEndGroup.test @@ -18,6 +18,11 @@ RUN: --whole-archive %p/Inputs/group/libfn.a --no-whole-archive \ RUN: %p/Inputs/group/libfn1.a --end-group -o %t3 +# Defined symbols in a shared library. +RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o --start-group \ +RUN: %p/Inputs/group/libfn2.so %p/Inputs/group/fn1.o %p/Inputs/group/fn.o \ +RUN: --end-group -o %t4 + # Test alias options too, as they are more widely used # Test group RUN: lld -flavor gnu -target x86_64 %p/Inputs/group/1.o '-(' \