From 5a25fd596238556a447d3e004624dafa0dfd59a4 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Wed, 7 Jan 2015 01:13:08 +0000 Subject: [PATCH] [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 --- lld/include/lld/Driver/GnuLdInputGraph.h | 36 ------------------ lld/lib/Driver/GnuLdDriver.cpp | 65 ++++++++++++++++++++++++++++---- lld/lib/Driver/GnuLdInputGraph.cpp | 65 -------------------------------- 3 files changed, 57 insertions(+), 109 deletions(-) diff --git a/lld/include/lld/Driver/GnuLdInputGraph.h b/lld/include/lld/Driver/GnuLdInputGraph.h index 69b81f9..ba06a87 100644 --- a/lld/include/lld/Driver/GnuLdInputGraph.h +++ b/lld/include/lld/Driver/GnuLdInputGraph.h @@ -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 _parser; - std::unique_ptr _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 &elt : _expandElements) - result.push_back(std::move(elt)); - return true; - } - -private: - InputGraph::InputElementVectorT _expandElements; -}; - } // namespace lld #endif diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index 2451ac8..8ec7d15 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -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> mb = + MemoryBuffer::getFileOrSTDIN(path); + if (std::error_code ec = mb.getError()) + return ec; + if (ctx.logInputFiles()) + diag << path << "\n"; + auto lexer = llvm::make_unique(std::move(mb.get())); + auto parser = llvm::make_unique(*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(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( + ctx, ctx.allocateString(path._path), attr)); + } + inputGraph->addInputElement(llvm::make_unique(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 inputFile(inputNode); ++numfiles; - inputGraph->addInputElement(std::move(inputFile)); + inputGraph->addInputElement( + llvm::make_unique(*ctx, path, attributes)); break; } diff --git a/lld/lib/Driver/GnuLdInputGraph.cpp b/lld/lib/Driver/GnuLdInputGraph.cpp index d13dbde..588576a 100644 --- a/lld/lib/Driver/GnuLdInputGraph.cpp +++ b/lld/lib/Driver/GnuLdInputGraph.cpp @@ -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 filePath = getPath(ctx); - if (std::error_code ec = filePath.getError()) - return ec; - ErrorOr> 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(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 inputFile(inputNode); - _expandElements.push_back(std::move(inputFile)); - ++numfiles; - } - _expandElements.push_back(llvm::make_unique(numfiles)); - } - return std::error_code(); -} -- 2.7.4