Index: include/lld/Core/Node.h =================================================================== --- include/lld/Core/Node.h +++ include/lld/Core/Node.h @@ -57,9 +57,7 @@ class FileNode : public Node { public: explicit FileNode(std::unique_ptr f) - : Node(Node::Kind::File), _file(std::move(f)) {} - - virtual ~FileNode() {} + : Node(Node::Kind::File), _file(std::move(f)), _asNeeded(false) {} static inline bool classof(const Node *a) { return a->kind() == Node::Kind::File; @@ -67,8 +65,12 @@ File *getFile() { return _file.get(); } + void setAsNeeded(bool val) { _asNeeded = val; } + bool asNeeded() const { return _asNeeded; } + protected: std::unique_ptr _file; + bool _asNeeded; }; } // namespace lld Index: include/lld/Core/SharedLibraryFile.h =================================================================== --- include/lld/Core/SharedLibraryFile.h +++ include/lld/Core/SharedLibraryFile.h @@ -31,6 +31,11 @@ /// symbol. Otherwise return nullptr. virtual const SharedLibraryAtom *exports(StringRef name, bool dataSymbolOnly) const = 0; + + // Returns DSO name. It's the soname (ELF), the install name (MachO) or + // the import name (Windows). + virtual StringRef getDSOName() const = 0; + protected: /// only subclasses of SharedLibraryFile can be instantiated explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {} Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -297,17 +297,14 @@ class Attributes { public: Attributes() - : _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false), - _isSysRooted(false) {} + : _isWholeArchive(false), _isDashlPrefix(false), _isSysRooted(false) {} void setWholeArchive(bool isWholeArchive) { _isWholeArchive = isWholeArchive; } - void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; } void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; } void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; } bool _isWholeArchive; - bool _asNeeded; bool _isDashlPrefix; bool _isSysRooted; }; Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -259,7 +259,6 @@ // TODO : Propagate Set WholeArchive/dashlPrefix ELFLinkingContext::Attributes attr; attr.setSysRooted(sysroot); - attr.setAsNeeded(path._asNeeded); attr.setDashlPrefix(path._isDashlPrefix); ErrorOr pathOrErr = path._isDashlPrefix @@ -358,6 +357,7 @@ int numfiles = 0; ELFLinkingContext::Attributes attributes; + bool asNeeded = false; bool _outputOptionSet = false; @@ -517,11 +517,11 @@ break; case OPT_as_needed: - attributes.setAsNeeded(true); + asNeeded = true; break; case OPT_no_as_needed: - attributes.setAsNeeded(false); + asNeeded = false; break; case OPT_defsym: { @@ -614,8 +614,9 @@ for (std::unique_ptr &file : files) { if (ctx->logInputFiles()) diagnostics << file->path() << "\n"; - ctx->getNodes().push_back( - std::unique_ptr(new FileNode(std::move(file)))); + auto node = std::unique_ptr(new FileNode(std::move(file))); + node->setAsNeeded(asNeeded); + ctx->getNodes().push_back(std::move(node)); } numfiles += files.size(); break; Index: lib/Driver/TODO.rst =================================================================== --- lib/Driver/TODO.rst +++ lib/Driver/TODO.rst @@ -41,7 +41,6 @@ * -y,--trace-symbol * -z (keywords need to be implemented) * --accept-unknown-input-arch,--no-accept-unknown-input-arch -* --as-needed,--no-as-needed * -Bdynamic,-dy,-call_shared * -Bgroup * -dn,-non_shared Index: lib/ReaderWriter/ELF/DynamicFile.h =================================================================== --- lib/ReaderWriter/ELF/DynamicFile.h +++ lib/ReaderWriter/ELF/DynamicFile.h @@ -55,6 +55,8 @@ *this, name, _soname, sym->second._symbol); } + StringRef getDSOName() const override { return _soname; } + protected: std::error_code doParse() override { std::error_code ec; Index: lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lib/ReaderWriter/ELF/OutputELFWriter.h +++ lib/ReaderWriter/ELF/OutputELFWriter.h @@ -14,6 +14,7 @@ #include "TargetLayout.h" #include "lld/Core/Instrumentation.h" #include "lld/Core/Parallel.h" +#include "lld/Core/SharedLibraryFile.h" #include "lld/ReaderWriter/ELFLinkingContext.h" #include "lld/ReaderWriter/Writer.h" #include "llvm/ADT/StringSet.h" @@ -143,6 +144,9 @@ LLD_UNIQUE_BUMP_PTR(HashSection) _hashTable; llvm::StringSet<> _soNeeded; /// @} + +private: + static StringRef maybeGetSOName(Node *node); }; //===----------------------------------------------------------------------===// @@ -177,6 +181,17 @@ _symtab->addSymbol(a, ELF::SHN_UNDEF); } +// Returns the DSO name for a given input file if it's a shared library +// file and not marked as --as-needed. +template +StringRef OutputELFWriter::maybeGetSOName(Node *node) { + if (auto *fnode = dyn_cast(node)) + if (!fnode->asNeeded()) + if (auto *file = dyn_cast(fnode->getFile())) + return file->getDSOName(); + return ""; +} + template void OutputELFWriter::buildDynamicSymbolTable(const File &file) { ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable"); @@ -189,6 +204,11 @@ if (isNeededTagRequired(sla)) _soNeeded.insert(sla->loadName()); } + for (const std::unique_ptr &node : _context.getNodes()) { + StringRef soname = maybeGetSOName(node.get()); + if (!soname.empty()) + _soNeeded.insert(soname); + } // Never mark the dynamic linker as DT_NEEDED _soNeeded.erase(sys::path::filename(_context.getInterpreter())); for (const auto &loadName : _soNeeded) { Index: lib/ReaderWriter/MachO/File.h =================================================================== --- lib/ReaderWriter/MachO/File.h +++ lib/ReaderWriter/MachO/File.h @@ -273,6 +273,8 @@ } } + StringRef getDSOName() const override { return _installName; } + std::error_code doParse() override { // Convert binary file to normalized mach-o. auto normFile = normalized::readBinary(_mb, _ctx->arch()); Index: test/elf/Mips/dynsym-table-1.test =================================================================== --- test/elf/Mips/dynsym-table-1.test +++ test/elf/Mips/dynsym-table-1.test @@ -10,7 +10,7 @@ # RUN: yaml2obj -format=elf -docnum 3 %s > %t-main.o # RUN: lld -flavor gnu -target mipsel -shared -o %t-bar.so %t-bar.o # RUN: lld -flavor gnu -target mipsel -shared -o %t-foo.so %t-foo.o %t-bar.so -# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe \ +# RUN: lld -flavor gnu -target mipsel -e T0 -o %t.exe --as-needed \ # RUN: %t-main.o %t-foo.so %t-bar.so # RUN: llvm-readobj -dt -dynamic-table %t.exe | FileCheck %s Index: test/elf/as-needed.test =================================================================== --- /dev/null +++ test/elf/as-needed.test @@ -0,0 +1,15 @@ +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: --as-needed %p/Inputs/shared.so-x86-64 %p/Inputs/libifunc.x86-64.so \ +RUN: -o %t1 -e main --allow-shlib-undefined +RUN: llvm-readobj -dynamic-table %t1 | FileCheck %s -check-prefix AS_NEEDED + +AS_NEEDED: NEEDED SharedLibrary (shared.so-x86-64) +AS_NEEDED-NOT: NEEDED SharedLibrary (libifunc.x86-64.so) + +RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/use-shared.x86-64 \ +RUN: %p/Inputs/shared.so-x86-64 %p/Inputs/libifunc.x86-64.so \ +RUN: -o %t2 -e main --allow-shlib-undefined +RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s -check-prefix NO_AS_NEEDED + +NO_AS_NEEDED: NEEDED SharedLibrary (shared.so-x86-64) +NO_AS_NEEDED: NEEDED SharedLibrary (libifunc.x86-64.so)