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
This commit is contained in:
Rafael Auler 2015-02-03 16:08:57 +00:00
parent 0285fc869d
commit ee95c3b5c5
5 changed files with 44 additions and 24 deletions

View 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

View 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;

View 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();
}

View 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() {

View 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());
}
}
}