From ee95c3b5c57f7b3e4fe369f543b14d2b677789f1 Mon Sep 17 00:00:00 2001 From: Rafael Auler Date: Tue, 3 Feb 2015 16:08:57 +0000 Subject: [PATCH] Make ELFLinkingContext own LinkerScript buffers Currently, no one owns script::Parser buffers, but yet ELFLinkingContext gets updated with StringRef pointers to data inside Parser buffers. Since this buffer is locally owned inside GnuLdDriver::evalLinkerScript(), as soon as this function finishes, all pointers in ELFLinkingContext that comes from linker scripts get invalid. The problem is that we need someone to own linker scripts data structures and, since ELFLinkingContext transports references to linker scripts data, we can simply make it also own all linker scripts data. Differential Revision: http://reviews.llvm.org/D7323 llvm-svn: 227975 --- lld/include/lld/ReaderWriter/ELFLinkingContext.h | 8 +++++++ lld/include/lld/ReaderWriter/LinkerScript.h | 16 ++++++++++--- lld/lib/Driver/GnuLdDriver.cpp | 9 +++++--- lld/lib/ReaderWriter/LinkerScript.cpp | 27 +++++++++++----------- .../linker-script-test/linker-script-test.cpp | 8 +++---- 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index 915492a..e544bcd 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/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 @@ public: 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 @@ protected: StringRefVector _rpathLinkList; std::map _absoluteSymbols; llvm::StringSet<> _dynamicallyExportedSymbols; + std::vector> _scripts; }; } // end namespace lld diff --git a/lld/include/lld/ReaderWriter/LinkerScript.h b/lld/include/lld/ReaderWriter/LinkerScript.h index 26f1ea4..39f0df8 100644 --- a/lld/include/lld/ReaderWriter/LinkerScript.h +++ b/lld/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 @@ public: /// 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 @@ private: // The top-level/entry-point linker script AST node LinkerScript _script; - Lexer &_lex; + Lexer _lex; // Current token being analyzed Token _tok; diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp index e4f757e..5100918 100644 --- a/lld/lib/Driver/GnuLdDriver.cpp +++ b/lld/lib/Driver/GnuLdDriver.cpp @@ -274,9 +274,10 @@ GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx, 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 @@ GnuLdDriver::evalLinkerScript(ELFLinkingContext &ctx, 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(); } diff --git a/lld/lib/ReaderWriter/LinkerScript.cpp b/lld/lib/ReaderWriter/LinkerScript.cpp index c8dbfdd..24dfe1b 100644 --- a/lld/lib/ReaderWriter/LinkerScript.cpp +++ b/lld/lib/ReaderWriter/LinkerScript.cpp @@ -892,67 +892,67 @@ void Sections::dump(raw_ostream &os) const { } // 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 @@ LinkerScript *Parser::parse() { 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() { diff --git a/lld/utils/linker-script-test/linker-script-test.cpp b/lld/utils/linker-script-test/linker-script-test.cpp index 9749898..027ecb3 100644 --- a/lld/utils/linker-script-test/linker-script-test.cpp +++ b/lld/utils/linker-script-test/linker-script-test.cpp @@ -48,10 +48,10 @@ int main(int argc, const char **argv) { 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()); + } } } -- 2.7.4