#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"
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;
StringRefVector _rpathLinkList;
std::map<std::string, uint64_t> _absoluteSymbols;
llvm::StringSet<> _dynamicallyExportedSymbols;
+ std::vector<std::unique_ptr<script::Parser>> _scripts;
};
} // end namespace lld
#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"
/// 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
// The top-level/entry-point linker script AST node
LinkerScript _script;
- Lexer &_lex;
+ Lexer _lex;
// Current token being analyzed
Token _tok;
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.
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();
}
}
// 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;
}
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() {
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());
+ }
}
}