blob: 1345bd4f9732cc0a336ce6829e7f36a9ef3e2a0a [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.
Rui Ueyama34f29242015-10-13 19:51:57 +000012// Results are written to Driver or Config object.
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000013//
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"
Rui Ueyamaf03f3cc2015-10-13 00:09:21 +000021#include "llvm/Support/Path.h"
Rui Ueyamaa47ee682015-10-11 01:53:04 +000022#include "llvm/Support/StringSaver.h"
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000023
24using namespace llvm;
25using namespace lld;
26using namespace lld::elf2;
27
28namespace {
29class LinkerScript {
30public:
Simon Atanasyan16b0cc92015-11-26 05:53:00 +000031 LinkerScript(BumpPtrAllocator *A, StringRef S, bool B)
32 : Saver(*A), Tokens(tokenize(S)), IsUnderSysroot(B) {}
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000033 void run();
34
35private:
36 static std::vector<StringRef> tokenize(StringRef S);
37 static StringRef skipSpace(StringRef S);
38 StringRef next();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000039 bool skip(StringRef Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000040 bool atEOF() { return Tokens.size() == Pos; }
41 void expect(StringRef Expect);
42
Rui Ueyama52a15092015-10-11 03:28:42 +000043 void addFile(StringRef Path);
44
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000045 void readAsNeeded();
Denis Protivensky90c50992015-10-08 06:48:38 +000046 void readEntry();
George Rimar83f406c2015-10-19 17:35:12 +000047 void readExtern();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000048 void readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000049 void readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000050 void readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000051 void readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000052 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000053 void readSearchDir();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000054 void readSections();
55
56 void readOutputSectionDescription();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000057
Rui Ueyamaa47ee682015-10-11 01:53:04 +000058 StringSaver Saver;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000059 std::vector<StringRef> Tokens;
60 size_t Pos = 0;
Simon Atanasyan16b0cc92015-11-26 05:53:00 +000061 bool IsUnderSysroot;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000062};
63}
64
65void LinkerScript::run() {
66 while (!atEOF()) {
67 StringRef Tok = next();
Davide Italiano10d268d2015-10-13 20:48:56 +000068 if (Tok == ";")
69 continue;
Denis Protivensky90c50992015-10-08 06:48:38 +000070 if (Tok == "ENTRY") {
71 readEntry();
George Rimar83f406c2015-10-19 17:35:12 +000072 } else if (Tok == "EXTERN") {
73 readExtern();
Rui Ueyama00f97272015-10-11 01:31:57 +000074 } else if (Tok == "GROUP" || Tok == "INPUT") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000075 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000076 } else if (Tok == "INCLUDE") {
77 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000078 } else if (Tok == "OUTPUT") {
79 readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000080 } else if (Tok == "OUTPUT_ARCH") {
81 readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000082 } else if (Tok == "OUTPUT_FORMAT") {
83 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000084 } else if (Tok == "SEARCH_DIR") {
85 readSearchDir();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000086 } else if (Tok == "SECTIONS") {
87 readSections();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000088 } else {
89 error("unknown directive: " + Tok);
90 }
91 }
92}
93
94// Split S into linker script tokens.
95std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
96 std::vector<StringRef> Ret;
97 for (;;) {
98 S = skipSpace(S);
99 if (S.empty())
100 return Ret;
101
102 // Quoted token
103 if (S.startswith("\"")) {
104 size_t E = S.find("\"", 1);
105 if (E == StringRef::npos)
106 error("unclosed quote");
Pete Cooper60259332016-01-22 23:46:37 +0000107 Ret.push_back(S.substr(1, E - 1));
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000108 S = S.substr(E + 1);
109 continue;
110 }
111
112 // Unquoted token
113 size_t Pos = S.find_first_not_of(
114 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
115 "0123456789_.$/\\~=+[]*?-:");
116 // A character that cannot start a word (which is usually a
117 // punctuation) forms a single character token.
118 if (Pos == 0)
119 Pos = 1;
120 Ret.push_back(S.substr(0, Pos));
121 S = S.substr(Pos);
122 }
123}
124
125// Skip leading whitespace characters or /**/-style comments.
126StringRef LinkerScript::skipSpace(StringRef S) {
127 for (;;) {
128 if (S.startswith("/*")) {
129 size_t E = S.find("*/", 2);
130 if (E == StringRef::npos)
131 error("unclosed comment in a linker script");
132 S = S.substr(E + 2);
133 continue;
134 }
135 size_t Size = S.size();
136 S = S.ltrim();
137 if (S.size() == Size)
138 return S;
139 }
140}
141
142StringRef LinkerScript::next() {
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000143 if (atEOF())
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000144 error("unexpected EOF");
145 return Tokens[Pos++];
146}
147
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000148bool LinkerScript::skip(StringRef Tok) {
149 if (atEOF())
150 error("unexpected EOF");
151 if (Tok != Tokens[Pos])
152 return false;
153 ++Pos;
154 return true;
155}
156
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000157void LinkerScript::expect(StringRef Expect) {
158 StringRef Tok = next();
159 if (Tok != Expect)
160 error(Expect + " expected, but got " + Tok);
161}
162
Rui Ueyama52a15092015-10-11 03:28:42 +0000163void LinkerScript::addFile(StringRef S) {
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000164 if (IsUnderSysroot && S.startswith("/")) {
165 SmallString<128> Path;
166 (Config->Sysroot + S).toStringRef(Path);
167 if (sys::fs::exists(Path)) {
168 Driver->addFile(Saver.save(Path.str()));
169 return;
170 }
171 }
172
Rui Ueyamaf03f3cc2015-10-13 00:09:21 +0000173 if (sys::path::is_absolute(S)) {
Rui Ueyama52a15092015-10-11 03:28:42 +0000174 Driver->addFile(S);
175 } else if (S.startswith("=")) {
176 if (Config->Sysroot.empty())
177 Driver->addFile(S.substr(1));
178 else
179 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
180 } else if (S.startswith("-l")) {
181 Driver->addFile(searchLibrary(S.substr(2)));
Simon Atanasyana1b8fc32015-11-26 20:23:46 +0000182 } else if (sys::fs::exists(S)) {
183 Driver->addFile(S);
Rui Ueyama52a15092015-10-11 03:28:42 +0000184 } else {
185 std::string Path = findFromSearchPaths(S);
186 if (Path.empty())
187 error("Unable to find " + S);
188 Driver->addFile(Saver.save(Path));
189 }
190}
191
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000192void LinkerScript::readAsNeeded() {
193 expect("(");
Rui Ueyama35da9b62015-10-11 20:59:12 +0000194 bool Orig = Config->AsNeeded;
195 Config->AsNeeded = true;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000196 for (;;) {
197 StringRef Tok = next();
198 if (Tok == ")")
Rui Ueyama35da9b62015-10-11 20:59:12 +0000199 break;
Rui Ueyama52a15092015-10-11 03:28:42 +0000200 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000201 }
Rui Ueyama35da9b62015-10-11 20:59:12 +0000202 Config->AsNeeded = Orig;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000203}
204
Denis Protivensky90c50992015-10-08 06:48:38 +0000205void LinkerScript::readEntry() {
206 // -e <symbol> takes predecence over ENTRY(<symbol>).
207 expect("(");
208 StringRef Tok = next();
209 if (Config->Entry.empty())
210 Config->Entry = Tok;
211 expect(")");
212}
213
George Rimar83f406c2015-10-19 17:35:12 +0000214void LinkerScript::readExtern() {
215 expect("(");
216 for (;;) {
217 StringRef Tok = next();
218 if (Tok == ")")
219 return;
220 Config->Undefined.push_back(Tok);
221 }
222}
223
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000224void LinkerScript::readGroup() {
225 expect("(");
226 for (;;) {
227 StringRef Tok = next();
228 if (Tok == ")")
229 return;
230 if (Tok == "AS_NEEDED") {
231 readAsNeeded();
232 continue;
233 }
Rui Ueyama52a15092015-10-11 03:28:42 +0000234 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000235 }
236}
237
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000238void LinkerScript::readInclude() {
239 StringRef Tok = next();
240 auto MBOrErr = MemoryBuffer::getFile(Tok);
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000241 error(MBOrErr, "cannot open " + Tok);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000242 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000243 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
244 std::vector<StringRef> V = tokenize(S);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000245 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000246}
247
Rui Ueyamaee592822015-10-07 00:25:09 +0000248void LinkerScript::readOutput() {
249 // -o <file> takes predecence over OUTPUT(<file>).
250 expect("(");
251 StringRef Tok = next();
252 if (Config->OutputFile.empty())
253 Config->OutputFile = Tok;
254 expect(")");
255}
256
Davide Italiano9159ce92015-10-12 21:50:08 +0000257void LinkerScript::readOutputArch() {
258 // Error checking only for now.
259 expect("(");
260 next();
261 expect(")");
262}
263
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000264void LinkerScript::readOutputFormat() {
265 // Error checking only for now.
266 expect("(");
267 next();
Davide Italiano6836c612015-10-12 21:08:41 +0000268 StringRef Tok = next();
269 if (Tok == ")")
270 return;
271 if (Tok != ",")
272 error("unexpected token: " + Tok);
273 next();
274 expect(",");
275 next();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000276 expect(")");
277}
278
Davide Italiano68a39a62015-10-08 17:51:41 +0000279void LinkerScript::readSearchDir() {
280 expect("(");
Rui Ueyama52a15092015-10-11 03:28:42 +0000281 Config->SearchPaths.push_back(next());
Davide Italiano68a39a62015-10-08 17:51:41 +0000282 expect(")");
283}
284
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000285void LinkerScript::readSections() {
286 expect("{");
287 while (!skip("}"))
288 readOutputSectionDescription();
289}
290
291void LinkerScript::readOutputSectionDescription() {
292 StringRef Name = next();
293 std::vector<StringRef> &InputSections = Config->OutputSections[Name];
294
295 expect(":");
296 expect("{");
297 while (!skip("}")) {
298 next(); // Skip input file name.
299 expect("(");
300 while (!skip(")"))
301 InputSections.push_back(next());
302 }
303}
304
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000305static bool isUnderSysroot(StringRef Path) {
306 if (Config->Sysroot == "")
307 return false;
308 for (; !Path.empty(); Path = sys::path::parent_path(Path))
309 if (sys::fs::equivalent(Config->Sysroot, Path))
310 return true;
311 return false;
312}
313
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000314// Entry point. The other functions or classes are private to this file.
Rui Ueyama83cd6e02016-01-06 20:11:55 +0000315void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000316 StringRef Path = MB.getBufferIdentifier();
317 LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000318}