blob: 7e0ed349821da2af4471b9e824967463c9141156 [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:
Rui Ueyama025d59b2016-02-02 20:27:59 +000036 void setError(const Twine &Msg);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000037 static std::vector<StringRef> tokenize(StringRef S);
38 static StringRef skipSpace(StringRef S);
Rui Ueyama025d59b2016-02-02 20:27:59 +000039 bool atEOF();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000040 StringRef next();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000041 bool skip(StringRef Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000042 void expect(StringRef Expect);
43
Rui Ueyama52a15092015-10-11 03:28:42 +000044 void addFile(StringRef Path);
45
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000046 void readAsNeeded();
Denis Protivensky90c50992015-10-08 06:48:38 +000047 void readEntry();
George Rimar83f406c2015-10-19 17:35:12 +000048 void readExtern();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000049 void readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000050 void readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000051 void readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000052 void readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000053 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000054 void readSearchDir();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000055 void readSections();
56
57 void readOutputSectionDescription();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000058
Rui Ueyamaa47ee682015-10-11 01:53:04 +000059 StringSaver Saver;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000060 std::vector<StringRef> Tokens;
Rui Ueyama025d59b2016-02-02 20:27:59 +000061 bool Error = false;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000062 size_t Pos = 0;
Simon Atanasyan16b0cc92015-11-26 05:53:00 +000063 bool IsUnderSysroot;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000064};
65}
66
67void LinkerScript::run() {
68 while (!atEOF()) {
69 StringRef Tok = next();
Davide Italiano10d268d2015-10-13 20:48:56 +000070 if (Tok == ";")
71 continue;
Denis Protivensky90c50992015-10-08 06:48:38 +000072 if (Tok == "ENTRY") {
73 readEntry();
George Rimar83f406c2015-10-19 17:35:12 +000074 } else if (Tok == "EXTERN") {
75 readExtern();
Rui Ueyama00f97272015-10-11 01:31:57 +000076 } else if (Tok == "GROUP" || Tok == "INPUT") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000077 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000078 } else if (Tok == "INCLUDE") {
79 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000080 } else if (Tok == "OUTPUT") {
81 readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000082 } else if (Tok == "OUTPUT_ARCH") {
83 readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000084 } else if (Tok == "OUTPUT_FORMAT") {
85 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000086 } else if (Tok == "SEARCH_DIR") {
87 readSearchDir();
Denis Protivensky8e3b38a2015-11-12 09:52:08 +000088 } else if (Tok == "SECTIONS") {
89 readSections();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000090 } else {
Rui Ueyama025d59b2016-02-02 20:27:59 +000091 setError("unknown directive: " + Tok);
92 return;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000093 }
94 }
95}
96
Rui Ueyama025d59b2016-02-02 20:27:59 +000097// We don't want to record cascading errors. Keep only the first one.
98void LinkerScript::setError(const Twine &Msg) {
99 if (Error)
100 return;
101 error(Msg);
102 Error = true;
103}
104
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000105// Split S into linker script tokens.
106std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
107 std::vector<StringRef> Ret;
108 for (;;) {
109 S = skipSpace(S);
110 if (S.empty())
111 return Ret;
112
113 // Quoted token
114 if (S.startswith("\"")) {
115 size_t E = S.find("\"", 1);
Rui Ueyama025d59b2016-02-02 20:27:59 +0000116 if (E == StringRef::npos) {
117 error("unclosed quote");
118 return {};
119 }
Pete Cooper60259332016-01-22 23:46:37 +0000120 Ret.push_back(S.substr(1, E - 1));
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000121 S = S.substr(E + 1);
122 continue;
123 }
124
125 // Unquoted token
126 size_t Pos = S.find_first_not_of(
127 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
128 "0123456789_.$/\\~=+[]*?-:");
129 // A character that cannot start a word (which is usually a
130 // punctuation) forms a single character token.
131 if (Pos == 0)
132 Pos = 1;
133 Ret.push_back(S.substr(0, Pos));
134 S = S.substr(Pos);
135 }
136}
137
138// Skip leading whitespace characters or /**/-style comments.
139StringRef LinkerScript::skipSpace(StringRef S) {
140 for (;;) {
141 if (S.startswith("/*")) {
142 size_t E = S.find("*/", 2);
Rui Ueyama025d59b2016-02-02 20:27:59 +0000143 if (E == StringRef::npos) {
144 error("unclosed comment in a linker script");
145 return "";
146 }
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000147 S = S.substr(E + 2);
148 continue;
149 }
150 size_t Size = S.size();
151 S = S.ltrim();
152 if (S.size() == Size)
153 return S;
154 }
155}
156
Rui Ueyama025d59b2016-02-02 20:27:59 +0000157// An errneous token is handled as if it were the last token before EOF.
158bool LinkerScript::atEOF() { return Error || Tokens.size() == Pos; }
159
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000160StringRef LinkerScript::next() {
Rui Ueyama025d59b2016-02-02 20:27:59 +0000161 if (Error)
162 return "";
163 if (atEOF()) {
164 setError("unexpected EOF");
165 return "";
166 }
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000167 return Tokens[Pos++];
168}
169
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000170bool LinkerScript::skip(StringRef Tok) {
Rui Ueyama025d59b2016-02-02 20:27:59 +0000171 if (Error)
172 return false;
173 if (atEOF()) {
174 setError("unexpected EOF");
175 return false;
176 }
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000177 if (Tok != Tokens[Pos])
178 return false;
179 ++Pos;
180 return true;
181}
182
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000183void LinkerScript::expect(StringRef Expect) {
Rui Ueyama025d59b2016-02-02 20:27:59 +0000184 if (Error)
185 return;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000186 StringRef Tok = next();
187 if (Tok != Expect)
Rui Ueyama025d59b2016-02-02 20:27:59 +0000188 setError(Expect + " expected, but got " + Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000189}
190
Rui Ueyama52a15092015-10-11 03:28:42 +0000191void LinkerScript::addFile(StringRef S) {
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000192 if (IsUnderSysroot && S.startswith("/")) {
193 SmallString<128> Path;
194 (Config->Sysroot + S).toStringRef(Path);
195 if (sys::fs::exists(Path)) {
196 Driver->addFile(Saver.save(Path.str()));
197 return;
198 }
199 }
200
Rui Ueyamaf03f3cc2015-10-13 00:09:21 +0000201 if (sys::path::is_absolute(S)) {
Rui Ueyama52a15092015-10-11 03:28:42 +0000202 Driver->addFile(S);
203 } else if (S.startswith("=")) {
204 if (Config->Sysroot.empty())
205 Driver->addFile(S.substr(1));
206 else
207 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
208 } else if (S.startswith("-l")) {
Rui Ueyama21eecb42016-02-02 21:13:09 +0000209 Driver->addLibrary(S.substr(2));
Simon Atanasyana1b8fc32015-11-26 20:23:46 +0000210 } else if (sys::fs::exists(S)) {
211 Driver->addFile(S);
Rui Ueyama52a15092015-10-11 03:28:42 +0000212 } else {
213 std::string Path = findFromSearchPaths(S);
214 if (Path.empty())
Rui Ueyama025d59b2016-02-02 20:27:59 +0000215 setError("Unable to find " + S);
216 else
217 Driver->addFile(Saver.save(Path));
Rui Ueyama52a15092015-10-11 03:28:42 +0000218 }
219}
220
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000221void LinkerScript::readAsNeeded() {
222 expect("(");
Rui Ueyama35da9b62015-10-11 20:59:12 +0000223 bool Orig = Config->AsNeeded;
224 Config->AsNeeded = true;
Rui Ueyama025d59b2016-02-02 20:27:59 +0000225 while (!Error) {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000226 StringRef Tok = next();
227 if (Tok == ")")
Rui Ueyama35da9b62015-10-11 20:59:12 +0000228 break;
Rui Ueyama52a15092015-10-11 03:28:42 +0000229 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000230 }
Rui Ueyama35da9b62015-10-11 20:59:12 +0000231 Config->AsNeeded = Orig;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000232}
233
Denis Protivensky90c50992015-10-08 06:48:38 +0000234void LinkerScript::readEntry() {
235 // -e <symbol> takes predecence over ENTRY(<symbol>).
236 expect("(");
237 StringRef Tok = next();
238 if (Config->Entry.empty())
239 Config->Entry = Tok;
240 expect(")");
241}
242
George Rimar83f406c2015-10-19 17:35:12 +0000243void LinkerScript::readExtern() {
244 expect("(");
Rui Ueyama025d59b2016-02-02 20:27:59 +0000245 while (!Error) {
George Rimar83f406c2015-10-19 17:35:12 +0000246 StringRef Tok = next();
247 if (Tok == ")")
248 return;
249 Config->Undefined.push_back(Tok);
250 }
251}
252
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000253void LinkerScript::readGroup() {
254 expect("(");
Rui Ueyama025d59b2016-02-02 20:27:59 +0000255 while (!Error) {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000256 StringRef Tok = next();
257 if (Tok == ")")
258 return;
259 if (Tok == "AS_NEEDED") {
260 readAsNeeded();
261 continue;
262 }
Rui Ueyama52a15092015-10-11 03:28:42 +0000263 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000264 }
265}
266
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000267void LinkerScript::readInclude() {
268 StringRef Tok = next();
269 auto MBOrErr = MemoryBuffer::getFile(Tok);
Rui Ueyama025d59b2016-02-02 20:27:59 +0000270 if (!MBOrErr) {
271 setError("cannot open " + Tok);
272 return;
273 }
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000274 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000275 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
276 std::vector<StringRef> V = tokenize(S);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000277 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000278}
279
Rui Ueyamaee592822015-10-07 00:25:09 +0000280void LinkerScript::readOutput() {
281 // -o <file> takes predecence over OUTPUT(<file>).
282 expect("(");
283 StringRef Tok = next();
284 if (Config->OutputFile.empty())
285 Config->OutputFile = Tok;
286 expect(")");
287}
288
Davide Italiano9159ce92015-10-12 21:50:08 +0000289void LinkerScript::readOutputArch() {
290 // Error checking only for now.
291 expect("(");
292 next();
293 expect(")");
294}
295
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000296void LinkerScript::readOutputFormat() {
297 // Error checking only for now.
298 expect("(");
299 next();
Davide Italiano6836c612015-10-12 21:08:41 +0000300 StringRef Tok = next();
301 if (Tok == ")")
302 return;
Rui Ueyama025d59b2016-02-02 20:27:59 +0000303 if (Tok != ",") {
304 setError("unexpected token: " + Tok);
305 return;
306 }
Davide Italiano6836c612015-10-12 21:08:41 +0000307 next();
308 expect(",");
309 next();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000310 expect(")");
311}
312
Davide Italiano68a39a62015-10-08 17:51:41 +0000313void LinkerScript::readSearchDir() {
314 expect("(");
Rui Ueyama52a15092015-10-11 03:28:42 +0000315 Config->SearchPaths.push_back(next());
Davide Italiano68a39a62015-10-08 17:51:41 +0000316 expect(")");
317}
318
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000319void LinkerScript::readSections() {
320 expect("{");
Rui Ueyama025d59b2016-02-02 20:27:59 +0000321 while (!Error && !skip("}"))
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000322 readOutputSectionDescription();
323}
324
325void LinkerScript::readOutputSectionDescription() {
326 StringRef Name = next();
327 std::vector<StringRef> &InputSections = Config->OutputSections[Name];
328
329 expect(":");
330 expect("{");
Rui Ueyama025d59b2016-02-02 20:27:59 +0000331 while (!Error && !skip("}")) {
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000332 next(); // Skip input file name.
333 expect("(");
Rui Ueyama025d59b2016-02-02 20:27:59 +0000334 while (!Error && !skip(")"))
Denis Protivensky8e3b38a2015-11-12 09:52:08 +0000335 InputSections.push_back(next());
336 }
337}
338
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000339static bool isUnderSysroot(StringRef Path) {
340 if (Config->Sysroot == "")
341 return false;
342 for (; !Path.empty(); Path = sys::path::parent_path(Path))
343 if (sys::fs::equivalent(Config->Sysroot, Path))
344 return true;
345 return false;
346}
347
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000348// Entry point. The other functions or classes are private to this file.
Rui Ueyama83cd6e02016-01-06 20:11:55 +0000349void elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
Simon Atanasyan16b0cc92015-11-26 05:53:00 +0000350 StringRef Path = MB.getBufferIdentifier();
351 LinkerScript(A, MB.getBuffer(), isUnderSysroot(Path)).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000352}