blob: 34fda2d2cc231fab8c8bd4bf5352363509564e8e [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:
Rui Ueyama983ed2b2015-10-01 15:23:09 +000029 LinkerScript(StringRef S) : Tokens(tokenize(S)) {}
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000030 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();
Denis Protivensky90c50992015-10-08 06:48:38 +000040 void readEntry();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000041 void readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000042 void readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000043 void readOutput();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000044 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000045 void readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000046
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000047 std::vector<StringRef> Tokens;
48 size_t Pos = 0;
Rui Ueyama31aa1f82015-10-11 01:31:55 +000049 static std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000050};
51}
52
53void LinkerScript::run() {
54 while (!atEOF()) {
55 StringRef Tok = next();
Denis Protivensky90c50992015-10-08 06:48:38 +000056 if (Tok == "ENTRY") {
57 readEntry();
58 } else if (Tok == "GROUP") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000059 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000060 } else if (Tok == "INCLUDE") {
61 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000062 } else if (Tok == "OUTPUT") {
63 readOutput();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000064 } else if (Tok == "OUTPUT_FORMAT") {
65 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000066 } else if (Tok == "SEARCH_DIR") {
67 readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000068 } else {
69 error("unknown directive: " + Tok);
70 }
71 }
72}
73
74// Split S into linker script tokens.
75std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
76 std::vector<StringRef> Ret;
77 for (;;) {
78 S = skipSpace(S);
79 if (S.empty())
80 return Ret;
81
82 // Quoted token
83 if (S.startswith("\"")) {
84 size_t E = S.find("\"", 1);
85 if (E == StringRef::npos)
86 error("unclosed quote");
87 Ret.push_back(S.substr(1, E));
88 S = S.substr(E + 1);
89 continue;
90 }
91
92 // Unquoted token
93 size_t Pos = S.find_first_not_of(
94 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
95 "0123456789_.$/\\~=+[]*?-:");
96 // A character that cannot start a word (which is usually a
97 // punctuation) forms a single character token.
98 if (Pos == 0)
99 Pos = 1;
100 Ret.push_back(S.substr(0, Pos));
101 S = S.substr(Pos);
102 }
103}
104
105// Skip leading whitespace characters or /**/-style comments.
106StringRef LinkerScript::skipSpace(StringRef S) {
107 for (;;) {
108 if (S.startswith("/*")) {
109 size_t E = S.find("*/", 2);
110 if (E == StringRef::npos)
111 error("unclosed comment in a linker script");
112 S = S.substr(E + 2);
113 continue;
114 }
115 size_t Size = S.size();
116 S = S.ltrim();
117 if (S.size() == Size)
118 return S;
119 }
120}
121
122StringRef LinkerScript::next() {
123 if (Pos == Tokens.size())
124 error("unexpected EOF");
125 return Tokens[Pos++];
126}
127
128void LinkerScript::expect(StringRef Expect) {
129 StringRef Tok = next();
130 if (Tok != Expect)
131 error(Expect + " expected, but got " + Tok);
132}
133
134void LinkerScript::readAsNeeded() {
135 expect("(");
136 for (;;) {
137 StringRef Tok = next();
138 if (Tok == ")")
139 return;
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000140 Driver->addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000141 }
142}
143
Denis Protivensky90c50992015-10-08 06:48:38 +0000144void LinkerScript::readEntry() {
145 // -e <symbol> takes predecence over ENTRY(<symbol>).
146 expect("(");
147 StringRef Tok = next();
148 if (Config->Entry.empty())
149 Config->Entry = Tok;
150 expect(")");
151}
152
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000153void LinkerScript::readGroup() {
154 expect("(");
155 for (;;) {
156 StringRef Tok = next();
157 if (Tok == ")")
158 return;
159 if (Tok == "AS_NEEDED") {
160 readAsNeeded();
161 continue;
162 }
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000163 Driver->addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000164 }
165}
166
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000167void LinkerScript::readInclude() {
168 StringRef Tok = next();
169 auto MBOrErr = MemoryBuffer::getFile(Tok);
170 error(MBOrErr, Twine("cannot open ") + Tok);
171 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
172 std::vector<StringRef> V = tokenize(MB->getMemBufferRef().getBuffer());
173 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
174 OwningMBs.push_back(std::move(MB)); // keep ownership of MB
175}
176
Rui Ueyamaee592822015-10-07 00:25:09 +0000177void LinkerScript::readOutput() {
178 // -o <file> takes predecence over OUTPUT(<file>).
179 expect("(");
180 StringRef Tok = next();
181 if (Config->OutputFile.empty())
182 Config->OutputFile = Tok;
183 expect(")");
184}
185
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000186void LinkerScript::readOutputFormat() {
187 // Error checking only for now.
188 expect("(");
189 next();
190 expect(")");
191}
192
Davide Italiano68a39a62015-10-08 17:51:41 +0000193void LinkerScript::readSearchDir() {
194 expect("(");
195 Config->InputSearchPaths.push_back(next());
196 expect(")");
197}
198
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000199std::vector<std::unique_ptr<MemoryBuffer>> LinkerScript::OwningMBs;
200
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000201// Entry point. The other functions or classes are private to this file.
Rui Ueyama983ed2b2015-10-01 15:23:09 +0000202void lld::elf2::readLinkerScript(MemoryBufferRef MB) {
203 LinkerScript(MB.getBuffer()).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000204}