blob: 4d05e10f7e4350d39230197f3b76666654056092 [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"
Rui Ueyamaa47ee682015-10-11 01:53:04 +000021#include "llvm/Support/StringSaver.h"
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000022
23using namespace llvm;
24using namespace lld;
25using namespace lld::elf2;
26
27namespace {
28class LinkerScript {
29public:
Rui Ueyamaa47ee682015-10-11 01:53:04 +000030 LinkerScript(BumpPtrAllocator *A, StringRef S)
31 : Saver(*A), Tokens(tokenize(S)) {}
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000032 void run();
33
34private:
35 static std::vector<StringRef> tokenize(StringRef S);
36 static StringRef skipSpace(StringRef S);
37 StringRef next();
38 bool atEOF() { return Tokens.size() == Pos; }
39 void expect(StringRef Expect);
40
Rui Ueyama52a15092015-10-11 03:28:42 +000041 void addFile(StringRef Path);
42
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000043 void readAsNeeded();
Denis Protivensky90c50992015-10-08 06:48:38 +000044 void readEntry();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000045 void readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000046 void readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000047 void readOutput();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000048 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000049 void readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000050
Rui Ueyamaa47ee682015-10-11 01:53:04 +000051 StringSaver Saver;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000052 std::vector<StringRef> Tokens;
53 size_t Pos = 0;
54};
55}
56
57void LinkerScript::run() {
58 while (!atEOF()) {
59 StringRef Tok = next();
Denis Protivensky90c50992015-10-08 06:48:38 +000060 if (Tok == "ENTRY") {
61 readEntry();
Rui Ueyama00f97272015-10-11 01:31:57 +000062 } else if (Tok == "GROUP" || Tok == "INPUT") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000063 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000064 } else if (Tok == "INCLUDE") {
65 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000066 } else if (Tok == "OUTPUT") {
67 readOutput();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000068 } else if (Tok == "OUTPUT_FORMAT") {
69 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000070 } else if (Tok == "SEARCH_DIR") {
71 readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000072 } else {
73 error("unknown directive: " + Tok);
74 }
75 }
76}
77
78// Split S into linker script tokens.
79std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
80 std::vector<StringRef> Ret;
81 for (;;) {
82 S = skipSpace(S);
83 if (S.empty())
84 return Ret;
85
86 // Quoted token
87 if (S.startswith("\"")) {
88 size_t E = S.find("\"", 1);
89 if (E == StringRef::npos)
90 error("unclosed quote");
91 Ret.push_back(S.substr(1, E));
92 S = S.substr(E + 1);
93 continue;
94 }
95
96 // Unquoted token
97 size_t Pos = S.find_first_not_of(
98 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
99 "0123456789_.$/\\~=+[]*?-:");
100 // A character that cannot start a word (which is usually a
101 // punctuation) forms a single character token.
102 if (Pos == 0)
103 Pos = 1;
104 Ret.push_back(S.substr(0, Pos));
105 S = S.substr(Pos);
106 }
107}
108
109// Skip leading whitespace characters or /**/-style comments.
110StringRef LinkerScript::skipSpace(StringRef S) {
111 for (;;) {
112 if (S.startswith("/*")) {
113 size_t E = S.find("*/", 2);
114 if (E == StringRef::npos)
115 error("unclosed comment in a linker script");
116 S = S.substr(E + 2);
117 continue;
118 }
119 size_t Size = S.size();
120 S = S.ltrim();
121 if (S.size() == Size)
122 return S;
123 }
124}
125
126StringRef LinkerScript::next() {
127 if (Pos == Tokens.size())
128 error("unexpected EOF");
129 return Tokens[Pos++];
130}
131
132void LinkerScript::expect(StringRef Expect) {
133 StringRef Tok = next();
134 if (Tok != Expect)
135 error(Expect + " expected, but got " + Tok);
136}
137
Rui Ueyama52a15092015-10-11 03:28:42 +0000138void LinkerScript::addFile(StringRef S) {
139 if (S.startswith("/")) {
140 Driver->addFile(S);
141 } else if (S.startswith("=")) {
142 if (Config->Sysroot.empty())
143 Driver->addFile(S.substr(1));
144 else
145 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
146 } else if (S.startswith("-l")) {
147 Driver->addFile(searchLibrary(S.substr(2)));
148 } else {
149 std::string Path = findFromSearchPaths(S);
150 if (Path.empty())
151 error("Unable to find " + S);
152 Driver->addFile(Saver.save(Path));
153 }
154}
155
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000156void LinkerScript::readAsNeeded() {
157 expect("(");
Rui Ueyama35da9b62015-10-11 20:59:12 +0000158 bool Orig = Config->AsNeeded;
159 Config->AsNeeded = true;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000160 for (;;) {
161 StringRef Tok = next();
162 if (Tok == ")")
Rui Ueyama35da9b62015-10-11 20:59:12 +0000163 break;
Rui Ueyama52a15092015-10-11 03:28:42 +0000164 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000165 }
Rui Ueyama35da9b62015-10-11 20:59:12 +0000166 Config->AsNeeded = Orig;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000167}
168
Denis Protivensky90c50992015-10-08 06:48:38 +0000169void LinkerScript::readEntry() {
170 // -e <symbol> takes predecence over ENTRY(<symbol>).
171 expect("(");
172 StringRef Tok = next();
173 if (Config->Entry.empty())
174 Config->Entry = Tok;
175 expect(")");
176}
177
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000178void LinkerScript::readGroup() {
179 expect("(");
180 for (;;) {
181 StringRef Tok = next();
182 if (Tok == ")")
183 return;
184 if (Tok == "AS_NEEDED") {
185 readAsNeeded();
186 continue;
187 }
Rui Ueyama52a15092015-10-11 03:28:42 +0000188 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000189 }
190}
191
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000192void LinkerScript::readInclude() {
193 StringRef Tok = next();
194 auto MBOrErr = MemoryBuffer::getFile(Tok);
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000195 error(MBOrErr, "cannot open " + Tok);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000196 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000197 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
198 std::vector<StringRef> V = tokenize(S);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000199 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000200}
201
Rui Ueyamaee592822015-10-07 00:25:09 +0000202void LinkerScript::readOutput() {
203 // -o <file> takes predecence over OUTPUT(<file>).
204 expect("(");
205 StringRef Tok = next();
206 if (Config->OutputFile.empty())
207 Config->OutputFile = Tok;
208 expect(")");
209}
210
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000211void LinkerScript::readOutputFormat() {
212 // Error checking only for now.
213 expect("(");
214 next();
Davide Italiano6836c612015-10-12 21:08:41 +0000215 StringRef Tok = next();
216 if (Tok == ")")
217 return;
218 if (Tok != ",")
219 error("unexpected token: " + Tok);
220 next();
221 expect(",");
222 next();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000223 expect(")");
224}
225
Davide Italiano68a39a62015-10-08 17:51:41 +0000226void LinkerScript::readSearchDir() {
227 expect("(");
Rui Ueyama52a15092015-10-11 03:28:42 +0000228 Config->SearchPaths.push_back(next());
Davide Italiano68a39a62015-10-08 17:51:41 +0000229 expect(")");
230}
231
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000232// Entry point. The other functions or classes are private to this file.
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000233void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
234 LinkerScript(A, MB.getBuffer()).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000235}