Index: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h +++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h @@ -17,6 +17,7 @@ #include "lld/Core/range.h" #include "lld/Core/Reader.h" #include "lld/Core/Writer.h" +#include "lld/ReaderWriter/LinkerScript.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/ELF.h" @@ -296,6 +297,12 @@ addSearchPath("=/usr/lib"); } + // We can parse several linker scripts via command line whose ASTs are stored + // in the current linking context via addLinkerScript(). + void addLinkerScript(std::unique_ptr script) { + _scripts.push_back(std::move(script)); + } + private: ELFLinkingContext() LLVM_DELETED_FUNCTION; @@ -335,6 +342,7 @@ StringRefVector _rpathLinkList; std::map _absoluteSymbols; llvm::StringSet<> _dynamicallyExportedSymbols; + std::vector> _scripts; }; } // end namespace lld Index: lld/trunk/include/lld/ReaderWriter/LinkerScript.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/LinkerScript.h +++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h @@ -15,6 +15,7 @@ #ifndef LLD_READER_WRITER_LINKER_SCRIPT_H #define LLD_READER_WRITER_LINKER_SCRIPT_H +#include "lld/Core/Error.h" #include "lld/Core/LLVM.h" #include "lld/Core/range.h" #include "llvm/ADT/StringSwitch.h" @@ -739,9 +740,18 @@ /// https://sourceware.org/binutils/docs/ld/Scripts.html class Parser { public: - explicit Parser(Lexer &lex) : _lex(lex), _peekAvailable(false) {} + explicit Parser(std::unique_ptr mb) + : _lex(std::move(mb)), _peekAvailable(false) {} - LinkerScript *parse(); + /// Let's not allow copying of Parser class because it would be expensive + /// to update all the AST pointers to a new buffer. + Parser(const Parser &instance) LLVM_DELETED_FUNCTION; + + /// Lex and parse the current memory buffer to create a linker script AST. + std::error_code parse(); + + /// Returns a reference to the top level node of the linker script AST. + LinkerScript *get() { return &_script; } private: /// Advances to the next token, either asking the Lexer to lex the next token @@ -981,7 +991,7 @@ // The top-level/entry-point linker script AST node LinkerScript _script; - Lexer &_lex; + Lexer _lex; // Current token being analyzed Token _tok; Index: lld/trunk/lib/Driver/GnuLdDriver.cpp =================================================================== --- lld/trunk/lib/Driver/GnuLdDriver.cpp +++ lld/trunk/lib/Driver/GnuLdDriver.cpp @@ -274,9 +274,10 @@ raw_ostream &diag) { // Read the script file from disk and parse. StringRef path = mb->getBufferIdentifier(); - auto lexer = llvm::make_unique(std::move(mb)); - auto parser = llvm::make_unique(*lexer); - script::LinkerScript *script = parser->parse(); + auto parser = llvm::make_unique(std::move(mb)); + if (std::error_code ec = parser->parse()) + return ec; + script::LinkerScript *script = parser->get(); if (!script) return LinkerScriptReaderError::parse_error; // Evaluate script commands. @@ -292,6 +293,8 @@ if (auto *output = dyn_cast(c)) ctx.setOutputPath(output->getOutputFileName()); } + // Transfer ownership of the script to the linking context + ctx.addLinkerScript(std::move(parser)); return std::error_code(); } Index: lld/trunk/lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/LinkerScript.cpp +++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp @@ -892,67 +892,67 @@ } // Parser functions -LinkerScript *Parser::parse() { +std::error_code Parser::parse() { // Get the first token. _lex.lex(_tok); // Parse top level commands. while (true) { switch (_tok._kind) { case Token::eof: - return &_script; + return std::error_code(); case Token::semicolon: consumeToken(); break; case Token::kw_output: { auto output = parseOutput(); if (!output) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(output); break; } case Token::kw_output_format: { auto outputFormat = parseOutputFormat(); if (!outputFormat) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(outputFormat); break; } case Token::kw_output_arch: { auto outputArch = parseOutputArch(); if (!outputArch) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(outputArch); break; } case Token::kw_group: { auto group = parseGroup(); if (!group) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(group); break; } case Token::kw_as_needed: // Not allowed at top level. error(_tok, "AS_NEEDED not allowed at top level."); - return nullptr; + return LinkerScriptReaderError::parse_error; case Token::kw_entry: { Entry *entry = parseEntry(); if (!entry) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(entry); break; } case Token::kw_search_dir: { SearchDir *searchDir = parseSearchDir(); if (!searchDir) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(searchDir); break; } case Token::kw_sections: { Sections *sections = parseSections(); if (!sections) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(sections); break; } @@ -962,18 +962,17 @@ case Token::kw_provide_hidden: { const Command *cmd = parseSymbolAssignment(); if (!cmd) - return nullptr; + return LinkerScriptReaderError::parse_error; _script._commands.push_back(cmd); break; } default: // Unexpected. error(_tok, "expected linker script command"); - return nullptr; + return LinkerScriptReaderError::parse_error; } } - - return nullptr; + return LinkerScriptReaderError::parse_error; } const Expression *Parser::parseFunctionCall() { Index: lld/trunk/utils/linker-script-test/linker-script-test.cpp =================================================================== --- lld/trunk/utils/linker-script-test/linker-script-test.cpp +++ lld/trunk/utils/linker-script-test/linker-script-test.cpp @@ -48,10 +48,10 @@ llvm::errs() << ec.message() << "\n"; return 1; } - Lexer l(std::move(mb.get())); - Parser p(l); - LinkerScript *ls = p.parse(); - if (ls) + Parser p(std::move(mb.get())); + if (!p.parse()) { + LinkerScript *ls = p.get(); ls->dump(llvm::outs()); + } } }