diff options
author | Rui Ueyama <ruiu@google.com> | 2015-09-30 17:23:26 +0000 |
---|---|---|
committer | Rui Ueyama <ruiu@google.com> | 2015-09-30 17:23:26 +0000 |
commit | f7c5fbb1ca982eebad6000d2ca53d8ad2cb922ff (patch) | |
tree | 50b666e68a6005280881e5fad68d97a096c9505b /lld/ELF/LinkerScript.cpp | |
parent | bf506b7d48b8d7e465ae6260cf51fec4e1788481 (diff) | |
download | bcm5719-llvm-f7c5fbb1ca982eebad6000d2ca53d8ad2cb922ff.tar.gz bcm5719-llvm-f7c5fbb1ca982eebad6000d2ca53d8ad2cb922ff.zip |
ELF2: Create LinkerScript.cpp and move code from DriverUtils to there.
llvm-svn: 248920
Diffstat (limited to 'lld/ELF/LinkerScript.cpp')
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp new file mode 100644 index 00000000000..746af74b6b9 --- /dev/null +++ b/lld/ELF/LinkerScript.cpp @@ -0,0 +1,156 @@ +//===- LinkerScript.cpp ---------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the parser/evaluator of the linker script. +// It does not construct an AST but consume linker script directives directly. +// Results are written to Symtab or Config object. +// +//===----------------------------------------------------------------------===// + +#include "Config.h" +#include "Driver.h" +#include "SymbolTable.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace lld; +using namespace lld::elf2; + +namespace { +class LinkerScript { +public: + LinkerScript(SymbolTable *T, StringRef S) : Symtab(T), Tokens(tokenize(S)) {} + void run(); + +private: + static std::vector<StringRef> tokenize(StringRef S); + static StringRef skipSpace(StringRef S); + StringRef next(); + bool atEOF() { return Tokens.size() == Pos; } + void expect(StringRef Expect); + + void readAsNeeded(); + void readGroup(); + void readOutputFormat(); + + SymbolTable *Symtab; + std::vector<StringRef> Tokens; + size_t Pos = 0; +}; +} + +void LinkerScript::run() { + while (!atEOF()) { + StringRef Tok = next(); + if (Tok == "GROUP") { + readGroup(); + } else if (Tok == "OUTPUT_FORMAT") { + readOutputFormat(); + } else { + error("unknown directive: " + Tok); + } + } +} + +// Split S into linker script tokens. +std::vector<StringRef> LinkerScript::tokenize(StringRef S) { + std::vector<StringRef> Ret; + for (;;) { + S = skipSpace(S); + if (S.empty()) + return Ret; + + // Quoted token + if (S.startswith("\"")) { + size_t E = S.find("\"", 1); + if (E == StringRef::npos) + error("unclosed quote"); + Ret.push_back(S.substr(1, E)); + S = S.substr(E + 1); + continue; + } + + // Unquoted token + size_t Pos = S.find_first_not_of( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789_.$/\\~=+[]*?-:"); + // A character that cannot start a word (which is usually a + // punctuation) forms a single character token. + if (Pos == 0) + Pos = 1; + Ret.push_back(S.substr(0, Pos)); + S = S.substr(Pos); + } +} + +// Skip leading whitespace characters or /**/-style comments. +StringRef LinkerScript::skipSpace(StringRef S) { + for (;;) { + if (S.startswith("/*")) { + size_t E = S.find("*/", 2); + if (E == StringRef::npos) + error("unclosed comment in a linker script"); + S = S.substr(E + 2); + continue; + } + size_t Size = S.size(); + S = S.ltrim(); + if (S.size() == Size) + return S; + } +} + +StringRef LinkerScript::next() { + if (Pos == Tokens.size()) + error("unexpected EOF"); + return Tokens[Pos++]; +} + +void LinkerScript::expect(StringRef Expect) { + StringRef Tok = next(); + if (Tok != Expect) + error(Expect + " expected, but got " + Tok); +} + +void LinkerScript::readAsNeeded() { + expect("("); + for (;;) { + StringRef Tok = next(); + if (Tok == ")") + return; + Symtab->addFile(createFile(openFile(Tok))); + } +} + +void LinkerScript::readGroup() { + expect("("); + for (;;) { + StringRef Tok = next(); + if (Tok == ")") + return; + if (Tok == "AS_NEEDED") { + readAsNeeded(); + continue; + } + Symtab->addFile(createFile(openFile(Tok))); + } +} + +void LinkerScript::readOutputFormat() { + // Error checking only for now. + expect("("); + next(); + expect(")"); +} + +// Entry point. The other functions or classes are private to this file. +void lld::elf2::readLinkerScript(SymbolTable *Symtab, MemoryBufferRef MB) { + LinkerScript(Symtab, MB.getBuffer()).run(); +} |