[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
This commit is contained in:
Rui Ueyama 2015-01-16 14:27:01 +00:00
parent 4286a9bd5a
commit fa7e8a663f
10 changed files with 57 additions and 13 deletions

View File

@ -57,9 +57,7 @@ private:
class FileNode : public Node {
public:
explicit FileNode(std::unique_ptr<File> 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> _file;
bool _asNeeded;
};
} // namespace lld

View File

@ -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) {}

View File

@ -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;
};

View File

@ -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<StringRef> 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> &file : files) {
if (ctx->logInputFiles())
diagnostics << file->path() << "\n";
ctx->getNodes().push_back(llvm::make_unique<FileNode>(std::move(file)));
auto node = llvm::make_unique<FileNode>(std::move(file));
node->setAsNeeded(asNeeded);
ctx->getNodes().push_back(std::move(node));
}
numfiles += files.size();
break;

View File

@ -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

View File

@ -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;

View File

@ -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<ELFT>) _hashTable;
llvm::StringSet<> _soNeeded;
/// @}
private:
static StringRef maybeGetSOName(Node *node);
};
//===----------------------------------------------------------------------===//
@ -177,6 +181,17 @@ void OutputELFWriter<ELFT>::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 <class ELFT>
StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) {
if (auto *fnode = dyn_cast<FileNode>(node))
if (!fnode->asNeeded())
if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile()))
return file->getDSOName();
return "";
}
template <class ELFT>
void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
@ -189,6 +204,11 @@ void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
if (isNeededTagRequired(sla))
_soNeeded.insert(sla->loadName());
}
for (const std::unique_ptr<Node> &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) {

View File

@ -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());

View File

@ -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

View File

@ -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)