Make ELFLinkingContext own LinkerScript buffers
authorRafael Auler <rafaelauler@gmail.com>
Tue, 3 Feb 2015 16:08:57 +0000 (16:08 +0000)
committerRafael Auler <rafaelauler@gmail.com>
Tue, 3 Feb 2015 16:08:57 +0000 (16:08 +0000)
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
lld/include/lld/ReaderWriter/LinkerScript.h
lld/lib/Driver/GnuLdDriver.cpp
lld/lib/ReaderWriter/LinkerScript.cpp
lld/utils/linker-script-test/linker-script-test.cpp

index 915492a..e544bcd 100644 (file)
@@ -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::Parser> script) {
+    _scripts.push_back(std::move(script));
+  }
+
 private:
   ELFLinkingContext() LLVM_DELETED_FUNCTION;
 
@@ -335,6 +342,7 @@ protected:
   StringRefVector _rpathLinkList;
   std::map<std::string, uint64_t> _absoluteSymbols;
   llvm::StringSet<> _dynamicallyExportedSymbols;
+  std::vector<std::unique_ptr<script::Parser>> _scripts;
 };
 } // end namespace lld
 
index 26f1ea4..39f0df8 100644 (file)
@@ -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<MemoryBuffer> 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;
index e4f757e..5100918 100644 (file)
@@ -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<script::Lexer>(std::move(mb));
-  auto parser = llvm::make_unique<script::Parser>(*lexer);
-  script::LinkerScript *script = parser->parse();
+  auto parser = llvm::make_unique<script::Parser>(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<script::Output>(c))
       ctx.setOutputPath(output->getOutputFileName());
   }
+  // Transfer ownership of the script to the linking context
+  ctx.addLinkerScript(std::move(parser));
   return std::error_code();
 }
 
index c8dbfdd..24dfe1b 100644 (file)
@@ -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() {
index 9749898..027ecb3 100644 (file)
@@ -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());
+    }
   }
 }