From fa7e8a663f8524af3d36f91cd402aa9fdfc91047 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 16 Jan 2015 14:27:01 +0000 Subject: [PATCH] [ELF] Add --as-needed. The previous default behavior of LLD is --as-needed. LLD linked against a DSO only if the DSO file was actually used to link an executable (i.e. at least one symbol was resolved using the shared library file.) In this patch I added a boolean flag to FileNode for --as-needed. I also added an accessor to DSO name to shared library file class. llvm-svn: 226274 --- lld/include/lld/Core/Node.h | 8 +++++--- lld/include/lld/Core/SharedLibraryFile.h | 5 +++++ .../lld/ReaderWriter/ELFLinkingContext.h | 5 +---- lld/lib/Driver/GnuLdDriver.cpp | 10 ++++++---- lld/lib/Driver/TODO.rst | 1 - lld/lib/ReaderWriter/ELF/DynamicFile.h | 2 ++ lld/lib/ReaderWriter/ELF/OutputELFWriter.h | 20 +++++++++++++++++++ lld/lib/ReaderWriter/MachO/File.h | 2 ++ lld/test/elf/Mips/dynsym-table-1.test | 2 +- lld/test/elf/as-needed.test | 15 ++++++++++++++ 10 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 lld/test/elf/as-needed.test diff --git a/lld/include/lld/Core/Node.h b/lld/include/lld/Core/Node.h index f902514efe41..37e8c67ab938 100644 --- a/lld/include/lld/Core/Node.h +++ b/lld/include/lld/Core/Node.h @@ -57,9 +57,7 @@ private: 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 @@ public: 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 diff --git a/lld/include/lld/Core/SharedLibraryFile.h b/lld/include/lld/Core/SharedLibraryFile.h index 42827f9759c3..3585e31cbd97 100644 --- a/lld/include/lld/Core/SharedLibraryFile.h +++ b/lld/include/lld/Core/SharedLibraryFile.h @@ -31,6 +31,11 @@ public: /// 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) {} diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index 9d7931b191be..85b4088577fe 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h @@ -297,17 +297,14 @@ public: 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; }; diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index ac25673cdafc..dc09847bae70 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -259,7 +259,6 @@ evaluateLinkerScript(ELFLinkingContext &ctx, StringRef path, // TODO : Propagate Set WholeArchive/dashlPrefix ELFLinkingContext::Attributes attr; attr.setSysRooted(sysroot); - attr.setAsNeeded(path._asNeeded); attr.setDashlPrefix(path._isDashlPrefix); ErrorOr pathOrErr = path._isDashlPrefix @@ -357,6 +356,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[], int numfiles = 0; ELFLinkingContext::Attributes attributes; + bool asNeeded = false; bool _outputOptionSet = false; @@ -516,11 +516,11 @@ bool GnuLdDriver::parse(int argc, const char *argv[], 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: { @@ -612,7 +612,9 @@ bool GnuLdDriver::parse(int argc, const char *argv[], for (std::unique_ptr &file : files) { if (ctx->logInputFiles()) diagnostics << file->path() << "\n"; - ctx->getNodes().push_back(llvm::make_unique(std::move(file))); + auto node = llvm::make_unique(std::move(file)); + node->setAsNeeded(asNeeded); + ctx->getNodes().push_back(std::move(node)); } numfiles += files.size(); break; diff --git a/lld/lib/Driver/TODO.rst b/lld/lib/Driver/TODO.rst index a0e4149c68a4..b9752e68eb13 100644 --- a/lld/lib/Driver/TODO.rst +++ b/lld/lib/Driver/TODO.rst @@ -41,7 +41,6 @@ Missing Options * -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 diff --git a/lld/lib/ReaderWriter/ELF/DynamicFile.h b/lld/lib/ReaderWriter/ELF/DynamicFile.h index 64139f52a1c1..473e42a9e236 100644 --- a/lld/lib/ReaderWriter/ELF/DynamicFile.h +++ b/lld/lib/ReaderWriter/ELF/DynamicFile.h @@ -55,6 +55,8 @@ public: *this, name, _soname, sym->second._symbol); } + StringRef getDSOName() const override { return _soname; } + protected: std::error_code doParse() override { std::error_code ec; diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index 56965c604672..c23bd5bf0272 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/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 @@ protected: LLD_UNIQUE_BUMP_PTR(HashSection) _hashTable; llvm::StringSet<> _soNeeded; /// @} + +private: + static StringRef maybeGetSOName(Node *node); }; //===----------------------------------------------------------------------===// @@ -177,6 +181,17 @@ void OutputELFWriter::buildStaticSymbolTable(const File &file) { _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 @@ void OutputELFWriter::buildDynamicSymbolTable(const File &file) { 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) { diff --git a/lld/lib/ReaderWriter/MachO/File.h b/lld/lib/ReaderWriter/MachO/File.h index ae0fbfbf34ef..7aec63585e48 100644 --- a/lld/lib/ReaderWriter/MachO/File.h +++ b/lld/lib/ReaderWriter/MachO/File.h @@ -273,6 +273,8 @@ public: } } + 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()); diff --git a/lld/test/elf/Mips/dynsym-table-1.test b/lld/test/elf/Mips/dynsym-table-1.test index 19f5889f39c6..43c48e730405 100644 --- a/lld/test/elf/Mips/dynsym-table-1.test +++ b/lld/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 diff --git a/lld/test/elf/as-needed.test b/lld/test/elf/as-needed.test new file mode 100644 index 000000000000..4477f0fe0ca6 --- /dev/null +++ b/lld/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)