Index: include/lld/Driver/GnuLdInputGraph.h =================================================================== --- include/lld/Driver/GnuLdInputGraph.h +++ 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 { @@ -104,51 +103,6 @@ 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; - } - - /// Unused functions for ELFGNULdScript Nodes. - ErrorOr getNextFile() override { - return make_error_code(InputGraphError::no_more_files); - } - - // Linker Script will be expanded and replaced with other elements - // by InputGraph::normalize(), so at link time it does not exist in - // the tree. No need to handle this message. - void resetNextIndex() override {} - -private: - InputGraph::InputElementVectorT _expandElements; -}; - } // namespace lld #endif Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ 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" @@ -218,6 +219,54 @@ 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) { @@ -530,19 +579,19 @@ } 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; } Index: lib/Driver/GnuLdInputGraph.cpp =================================================================== --- lib/Driver/GnuLdInputGraph.cpp +++ lib/Driver/GnuLdInputGraph.cpp @@ -63,68 +63,3 @@ } 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(); -}