[ELF] Remove {ELF,}GNULinkerScript.

Instead of representing a linker script file as an "InputElement",
parse and evaluate scripts in the driver as we see them.

Linker scripts are not regular input files (regular file is one of
object, archive, or shared library file). They are more like
extended command line options. Linker script handling was needlessly
complicated because of that inappropriate abstraction (besides
excessive class hierarchy -- there is no such thing like ELF linker
script but we had two classes there for some reason.)

LinkerScript was one of a few remaining InputElement subclasses
that can be expanded to multiple files. With this patch, we are one
step closer to retire InputElement.

http://reviews.llvm.org/D6648

llvm-svn: 225330
This commit is contained in:
Rui Ueyama 2015-01-07 01:13:08 +00:00
parent 5310c1e954
commit 5a25fd5962
3 changed files with 57 additions and 109 deletions

View File

@ -21,7 +21,6 @@
#include "lld/Core/InputGraph.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "lld/ReaderWriter/LinkerScript.h"
namespace lld {
@ -81,41 +80,6 @@ private:
const Attributes _attributes;
};
/// \brief Parse GNU Linker scripts.
class GNULdScript : public FileNode {
public:
GNULdScript(ELFLinkingContext &ctx, StringRef userPath)
: FileNode(userPath), _elfLinkingContext(ctx), _linkerScript(nullptr) {}
/// \brief Parse the linker script.
std::error_code parse(const LinkingContext &, raw_ostream &) override;
protected:
ELFLinkingContext &_elfLinkingContext;
std::unique_ptr<script::Parser> _parser;
std::unique_ptr<script::Lexer> _lexer;
script::LinkerScript *_linkerScript;
};
/// \brief Handle ELF style with GNU Linker scripts.
class ELFGNULdScript : public GNULdScript {
public:
ELFGNULdScript(ELFLinkingContext &ctx, StringRef userPath)
: GNULdScript(ctx, userPath) {}
std::error_code parse(const LinkingContext &ctx,
raw_ostream &diagnostics) override;
bool getReplacements(InputGraph::InputElementVectorT &result) override {
for (std::unique_ptr<InputElement> &elt : _expandElements)
result.push_back(std::move(elt));
return true;
}
private:
InputGraph::InputElementVectorT _expandElements;
};
} // namespace lld
#endif

View File

@ -15,6 +15,7 @@
#include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h"
#include "lld/ReaderWriter/LinkerScript.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
@ -217,6 +218,54 @@ static bool isLinkerScript(StringRef path, raw_ostream &diag) {
return magic == llvm::sys::fs::file_magic::unknown;
}
static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
if (sysroot.empty())
return false;
while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
path = llvm::sys::path::parent_path(path);
return !path.empty();
}
static std::error_code
evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
StringRef path, raw_ostream &diag) {
// Read the script file from disk and parse.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(path);
if (std::error_code ec = mb.getError())
return ec;
if (ctx.logInputFiles())
diag << path << "\n";
auto lexer = llvm::make_unique<script::Lexer>(std::move(mb.get()));
auto parser = llvm::make_unique<script::Parser>(*lexer);
script::LinkerScript *script = parser->parse();
if (!script)
return LinkerScriptReaderError::parse_error;
// Evaluate script commands.
// Currently we only recognize GROUP() command.
bool sysroot = (!ctx.getSysroot().empty()
&& isPathUnderSysroot(ctx.getSysroot(), path));
for (const script::Command *c : script->_commands) {
auto *group = dyn_cast<script::Group>(c);
if (!group)
continue;
int numfiles = 0;
for (const script::Path &path : group->getPaths()) {
// TODO : Propagate Set WholeArchive/dashlPrefix
ELFFileNode::Attributes attr;
attr.setSysRooted(sysroot);
attr.setAsNeeded(path._asNeeded);
attr.setDashlPrefix(path._isDashlPrefix);
++numfiles;
inputGraph->addInputElement(llvm::make_unique<ELFFileNode>(
ctx, ctx.allocateString(path._path), attr));
}
inputGraph->addInputElement(llvm::make_unique<GroupEnd>(numfiles));
}
return std::error_code();
}
bool GnuLdDriver::applyEmulation(llvm::Triple &triple,
llvm::opt::InputArgList &args,
raw_ostream &diagnostics) {
@ -529,19 +578,19 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
}
bool isScript =
(!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics));
FileNode *inputNode = nullptr;
if (isScript) {
inputNode = new ELFGNULdScript(*ctx, realpath);
if (inputNode->parse(*ctx, diagnostics)) {
diagnostics << path << ": Error parsing linker script\n";
std::error_code ec = evaluateLinkerScript(
*ctx, inputGraph.get(), realpath, diagnostics);
if (ec) {
diagnostics << path << ": Error parsing linker script: "
<< ec.message() << "\n";
return false;
}
} else {
inputNode = new ELFFileNode(*ctx, path, attributes);
break;
}
std::unique_ptr<InputElement> inputFile(inputNode);
++numfiles;
inputGraph->addInputElement(std::move(inputFile));
inputGraph->addInputElement(
llvm::make_unique<ELFFileNode>(*ctx, path, attributes));
break;
}

View File

@ -63,68 +63,3 @@ std::error_code ELFFileNode::parse(const LinkingContext &ctx,
}
return ctx.registry().parseFile(std::move(mb.get()), _files);
}
/// \brief Parse the GnuLD Script
std::error_code GNULdScript::parse(const LinkingContext &ctx,
raw_ostream &diagnostics) {
ErrorOr<StringRef> filePath = getPath(ctx);
if (std::error_code ec = filePath.getError())
return ec;
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(*filePath);
if (std::error_code ec = mb.getError())
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
_lexer.reset(new script::Lexer(std::move(mb.get())));
_parser.reset(new script::Parser(*_lexer.get()));
_linkerScript = _parser->parse();
if (!_linkerScript)
return LinkerScriptReaderError::parse_error;
return std::error_code();
}
static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
if (sysroot.empty())
return false;
while (!path.empty() && !llvm::sys::fs::equivalent(sysroot, path))
path = llvm::sys::path::parent_path(path);
return !path.empty();
}
/// \brief Handle GnuLD script for ELF.
std::error_code ELFGNULdScript::parse(const LinkingContext &ctx,
raw_ostream &diagnostics) {
ELFFileNode::Attributes attributes;
if (std::error_code ec = GNULdScript::parse(ctx, diagnostics))
return ec;
StringRef sysRoot = _elfLinkingContext.getSysroot();
if (!sysRoot.empty() && isPathUnderSysroot(sysRoot, *getPath(ctx)))
attributes.setSysRooted(true);
for (const script::Command *c : _linkerScript->_commands) {
auto *group = dyn_cast<script::Group>(c);
if (!group)
continue;
size_t numfiles = 0;
for (const script::Path &path : group->getPaths()) {
// TODO : Propagate Set WholeArchive/dashlPrefix
attributes.setAsNeeded(path._asNeeded);
attributes.setDashlPrefix(path._isDashlPrefix);
auto inputNode = new ELFFileNode(
_elfLinkingContext, _elfLinkingContext.allocateString(path._path),
attributes);
std::unique_ptr<InputElement> inputFile(inputNode);
_expandElements.push_back(std::move(inputFile));
++numfiles;
}
_expandElements.push_back(llvm::make_unique<GroupEnd>(numfiles));
}
return std::error_code();
}