Files
llvm/lld/ELF/LinkerScript.cpp
Rui Ueyama 983ed2b749 ELF2: Define Driver::addFile() as a one-stop place to open a file.
Opening a file and dispatching to readLinkerScript() or createFile()
is a common operation. We want to use that at least from Driver and
from LinkerScript. In COFF, we had the same problem. This patch
resolves the problem in the same way as we did for COFF.

Now, if you have a path that you want to open, just call
Driver->addFile(StringRef). That function opens the file and handles
that as if that were given by command line. This function is the
only place we call identify_magic().

llvm-svn: 249023
2015-10-01 15:23:09 +00:00

156 lines
3.6 KiB
C++

//===- 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(StringRef S) : 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();
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;
Driver->addFile(Tok);
}
}
void LinkerScript::readGroup() {
expect("(");
for (;;) {
StringRef Tok = next();
if (Tok == ")")
return;
if (Tok == "AS_NEEDED") {
readAsNeeded();
continue;
}
Driver->addFile(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(MemoryBufferRef MB) {
LinkerScript(MB.getBuffer()).run();
}