blob: 746af74b6b905b317fe5b511abe8f84913c5fe50 [file] [log] [blame]
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +00001//===- LinkerScript.cpp ---------------------------------------------------===//
2//
3// The LLVM Linker
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains the parser/evaluator of the linker script.
11// It does not construct an AST but consume linker script directives directly.
12// Results are written to Symtab or Config object.
13//
14//===----------------------------------------------------------------------===//
15
16#include "Config.h"
17#include "Driver.h"
18#include "SymbolTable.h"
19#include "llvm/Support/FileSystem.h"
20#include "llvm/Support/MemoryBuffer.h"
21
22using namespace llvm;
23using namespace lld;
24using namespace lld::elf2;
25
26namespace {
27class LinkerScript {
28public:
29 LinkerScript(SymbolTable *T, StringRef S) : Symtab(T), Tokens(tokenize(S)) {}
30 void run();
31
32private:
33 static std::vector<StringRef> tokenize(StringRef S);
34 static StringRef skipSpace(StringRef S);
35 StringRef next();
36 bool atEOF() { return Tokens.size() == Pos; }
37 void expect(StringRef Expect);
38
39 void readAsNeeded();
40 void readGroup();
41 void readOutputFormat();
42
43 SymbolTable *Symtab;
44 std::vector<StringRef> Tokens;
45 size_t Pos = 0;
46};
47}
48
49void LinkerScript::run() {
50 while (!atEOF()) {
51 StringRef Tok = next();
52 if (Tok == "GROUP") {
53 readGroup();
54 } else if (Tok == "OUTPUT_FORMAT") {
55 readOutputFormat();
56 } else {
57 error("unknown directive: " + Tok);
58 }
59 }
60}
61
62// Split S into linker script tokens.
63std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
64 std::vector<StringRef> Ret;
65 for (;;) {
66 S = skipSpace(S);
67 if (S.empty())
68 return Ret;
69
70 // Quoted token
71 if (S.startswith("\"")) {
72 size_t E = S.find("\"", 1);
73 if (E == StringRef::npos)
74 error("unclosed quote");
75 Ret.push_back(S.substr(1, E));
76 S = S.substr(E + 1);
77 continue;
78 }
79
80 // Unquoted token
81 size_t Pos = S.find_first_not_of(
82 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
83 "0123456789_.$/\\~=+[]*?-:");
84 // A character that cannot start a word (which is usually a
85 // punctuation) forms a single character token.
86 if (Pos == 0)
87 Pos = 1;
88 Ret.push_back(S.substr(0, Pos));
89 S = S.substr(Pos);
90 }
91}
92
93// Skip leading whitespace characters or /**/-style comments.
94StringRef LinkerScript::skipSpace(StringRef S) {
95 for (;;) {
96 if (S.startswith("/*")) {
97 size_t E = S.find("*/", 2);
98 if (E == StringRef::npos)
99 error("unclosed comment in a linker script");
100 S = S.substr(E + 2);
101 continue;
102 }
103 size_t Size = S.size();
104 S = S.ltrim();
105 if (S.size() == Size)
106 return S;
107 }
108}
109
110StringRef LinkerScript::next() {
111 if (Pos == Tokens.size())
112 error("unexpected EOF");
113 return Tokens[Pos++];
114}
115
116void LinkerScript::expect(StringRef Expect) {
117 StringRef Tok = next();
118 if (Tok != Expect)
119 error(Expect + " expected, but got " + Tok);
120}
121
122void LinkerScript::readAsNeeded() {
123 expect("(");
124 for (;;) {
125 StringRef Tok = next();
126 if (Tok == ")")
127 return;
128 Symtab->addFile(createFile(openFile(Tok)));
129 }
130}
131
132void LinkerScript::readGroup() {
133 expect("(");
134 for (;;) {
135 StringRef Tok = next();
136 if (Tok == ")")
137 return;
138 if (Tok == "AS_NEEDED") {
139 readAsNeeded();
140 continue;
141 }
142 Symtab->addFile(createFile(openFile(Tok)));
143 }
144}
145
146void LinkerScript::readOutputFormat() {
147 // Error checking only for now.
148 expect("(");
149 next();
150 expect(")");
151}
152
153// Entry point. The other functions or classes are private to this file.
154void lld::elf2::readLinkerScript(SymbolTable *Symtab, MemoryBufferRef MB) {
155 LinkerScript(Symtab, MB.getBuffer()).run();
156}