blob: ddd82663eee3b160431ee06928207f0fcea42fcf [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();
Davide Italiano9159ce92015-10-12 21:50:08 +000048 void readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000049 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000050 void readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000051
Rui Ueyamaa47ee682015-10-11 01:53:04 +000052 StringSaver Saver;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000053 std::vector<StringRef> Tokens;
54 size_t Pos = 0;
55};
56}
57
58void LinkerScript::run() {
59 while (!atEOF()) {
60 StringRef Tok = next();
Denis Protivensky90c50992015-10-08 06:48:38 +000061 if (Tok == "ENTRY") {
62 readEntry();
Rui Ueyama00f97272015-10-11 01:31:57 +000063 } else if (Tok == "GROUP" || Tok == "INPUT") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000064 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000065 } else if (Tok == "INCLUDE") {
66 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000067 } else if (Tok == "OUTPUT") {
68 readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000069 } else if (Tok == "OUTPUT_ARCH") {
70 readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000071 } else if (Tok == "OUTPUT_FORMAT") {
72 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000073 } else if (Tok == "SEARCH_DIR") {
74 readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000075 } else {
76 error("unknown directive: " + Tok);
77 }
78 }
79}
80
81// Split S into linker script tokens.
82std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
83 std::vector<StringRef> Ret;
84 for (;;) {
85 S = skipSpace(S);
86 if (S.empty())
87 return Ret;
88
89 // Quoted token
90 if (S.startswith("\"")) {
91 size_t E = S.find("\"", 1);
92 if (E == StringRef::npos)
93 error("unclosed quote");
94 Ret.push_back(S.substr(1, E));
95 S = S.substr(E + 1);
96 continue;
97 }
98
99 // Unquoted token
100 size_t Pos = S.find_first_not_of(
101 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
102 "0123456789_.$/\\~=+[]*?-:");
103 // A character that cannot start a word (which is usually a
104 // punctuation) forms a single character token.
105 if (Pos == 0)
106 Pos = 1;
107 Ret.push_back(S.substr(0, Pos));
108 S = S.substr(Pos);
109 }
110}
111
112// Skip leading whitespace characters or /**/-style comments.
113StringRef LinkerScript::skipSpace(StringRef S) {
114 for (;;) {
115 if (S.startswith("/*")) {
116 size_t E = S.find("*/", 2);
117 if (E == StringRef::npos)
118 error("unclosed comment in a linker script");
119 S = S.substr(E + 2);
120 continue;
121 }
122 size_t Size = S.size();
123 S = S.ltrim();
124 if (S.size() == Size)
125 return S;
126 }
127}
128
129StringRef LinkerScript::next() {
130 if (Pos == Tokens.size())
131 error("unexpected EOF");
132 return Tokens[Pos++];
133}
134
135void LinkerScript::expect(StringRef Expect) {
136 StringRef Tok = next();
137 if (Tok != Expect)
138 error(Expect + " expected, but got " + Tok);
139}
140
Rui Ueyama52a15092015-10-11 03:28:42 +0000141void LinkerScript::addFile(StringRef S) {
142 if (S.startswith("/")) {
143 Driver->addFile(S);
144 } else if (S.startswith("=")) {
145 if (Config->Sysroot.empty())
146 Driver->addFile(S.substr(1));
147 else
148 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
149 } else if (S.startswith("-l")) {
150 Driver->addFile(searchLibrary(S.substr(2)));
151 } else {
152 std::string Path = findFromSearchPaths(S);
153 if (Path.empty())
154 error("Unable to find " + S);
155 Driver->addFile(Saver.save(Path));
156 }
157}
158
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000159void LinkerScript::readAsNeeded() {
160 expect("(");
Rui Ueyama35da9b62015-10-11 20:59:12 +0000161 bool Orig = Config->AsNeeded;
162 Config->AsNeeded = true;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000163 for (;;) {
164 StringRef Tok = next();
165 if (Tok == ")")
Rui Ueyama35da9b62015-10-11 20:59:12 +0000166 break;
Rui Ueyama52a15092015-10-11 03:28:42 +0000167 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000168 }
Rui Ueyama35da9b62015-10-11 20:59:12 +0000169 Config->AsNeeded = Orig;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000170}
171
Denis Protivensky90c50992015-10-08 06:48:38 +0000172void LinkerScript::readEntry() {
173 // -e <symbol> takes predecence over ENTRY(<symbol>).
174 expect("(");
175 StringRef Tok = next();
176 if (Config->Entry.empty())
177 Config->Entry = Tok;
178 expect(")");
179}
180
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000181void LinkerScript::readGroup() {
182 expect("(");
183 for (;;) {
184 StringRef Tok = next();
185 if (Tok == ")")
186 return;
187 if (Tok == "AS_NEEDED") {
188 readAsNeeded();
189 continue;
190 }
Rui Ueyama52a15092015-10-11 03:28:42 +0000191 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000192 }
193}
194
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000195void LinkerScript::readInclude() {
196 StringRef Tok = next();
197 auto MBOrErr = MemoryBuffer::getFile(Tok);
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000198 error(MBOrErr, "cannot open " + Tok);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000199 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000200 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
201 std::vector<StringRef> V = tokenize(S);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000202 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000203}
204
Rui Ueyamaee592822015-10-07 00:25:09 +0000205void LinkerScript::readOutput() {
206 // -o <file> takes predecence over OUTPUT(<file>).
207 expect("(");
208 StringRef Tok = next();
209 if (Config->OutputFile.empty())
210 Config->OutputFile = Tok;
211 expect(")");
212}
213
Davide Italiano9159ce92015-10-12 21:50:08 +0000214void LinkerScript::readOutputArch() {
215 // Error checking only for now.
216 expect("(");
217 next();
218 expect(")");
219}
220
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000221void LinkerScript::readOutputFormat() {
222 // Error checking only for now.
223 expect("(");
224 next();
Davide Italiano6836c612015-10-12 21:08:41 +0000225 StringRef Tok = next();
226 if (Tok == ")")
227 return;
228 if (Tok != ",")
229 error("unexpected token: " + Tok);
230 next();
231 expect(",");
232 next();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000233 expect(")");
234}
235
Davide Italiano68a39a62015-10-08 17:51:41 +0000236void LinkerScript::readSearchDir() {
237 expect("(");
Rui Ueyama52a15092015-10-11 03:28:42 +0000238 Config->SearchPaths.push_back(next());
Davide Italiano68a39a62015-10-08 17:51:41 +0000239 expect(")");
240}
241
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000242// Entry point. The other functions or classes are private to this file.
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000243void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
244 LinkerScript(A, MB.getBuffer()).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000245}