blob: 2a63be4ca5de99d984ec284a235ccdf06f4e9125 [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:
Rui Ueyamaa47ee682015-10-11 01:53:04 +000031 LinkerScript(BumpPtrAllocator *A, StringRef S)
32 : Saver(*A), Tokens(tokenize(S)) {}
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();
39 bool atEOF() { return Tokens.size() == Pos; }
40 void expect(StringRef Expect);
41
Rui Ueyama52a15092015-10-11 03:28:42 +000042 void addFile(StringRef Path);
43
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000044 void readAsNeeded();
Denis Protivensky90c50992015-10-08 06:48:38 +000045 void readEntry();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000046 void readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000047 void readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000048 void readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000049 void readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000050 void readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000051 void readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000052
Rui Ueyamaa47ee682015-10-11 01:53:04 +000053 StringSaver Saver;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000054 std::vector<StringRef> Tokens;
55 size_t Pos = 0;
56};
57}
58
59void LinkerScript::run() {
60 while (!atEOF()) {
61 StringRef Tok = next();
Davide Italiano10d268d2015-10-13 20:48:56 +000062 if (Tok == ";")
63 continue;
Denis Protivensky90c50992015-10-08 06:48:38 +000064 if (Tok == "ENTRY") {
65 readEntry();
Rui Ueyama00f97272015-10-11 01:31:57 +000066 } else if (Tok == "GROUP" || Tok == "INPUT") {
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000067 readGroup();
Rui Ueyama31aa1f82015-10-11 01:31:55 +000068 } else if (Tok == "INCLUDE") {
69 readInclude();
Rui Ueyamaee592822015-10-07 00:25:09 +000070 } else if (Tok == "OUTPUT") {
71 readOutput();
Davide Italiano9159ce92015-10-12 21:50:08 +000072 } else if (Tok == "OUTPUT_ARCH") {
73 readOutputArch();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000074 } else if (Tok == "OUTPUT_FORMAT") {
75 readOutputFormat();
Davide Italiano68a39a62015-10-08 17:51:41 +000076 } else if (Tok == "SEARCH_DIR") {
77 readSearchDir();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +000078 } else {
79 error("unknown directive: " + Tok);
80 }
81 }
82}
83
84// Split S into linker script tokens.
85std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
86 std::vector<StringRef> Ret;
87 for (;;) {
88 S = skipSpace(S);
89 if (S.empty())
90 return Ret;
91
92 // Quoted token
93 if (S.startswith("\"")) {
94 size_t E = S.find("\"", 1);
95 if (E == StringRef::npos)
96 error("unclosed quote");
97 Ret.push_back(S.substr(1, E));
98 S = S.substr(E + 1);
99 continue;
100 }
101
102 // Unquoted token
103 size_t Pos = S.find_first_not_of(
104 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
105 "0123456789_.$/\\~=+[]*?-:");
106 // A character that cannot start a word (which is usually a
107 // punctuation) forms a single character token.
108 if (Pos == 0)
109 Pos = 1;
110 Ret.push_back(S.substr(0, Pos));
111 S = S.substr(Pos);
112 }
113}
114
115// Skip leading whitespace characters or /**/-style comments.
116StringRef LinkerScript::skipSpace(StringRef S) {
117 for (;;) {
118 if (S.startswith("/*")) {
119 size_t E = S.find("*/", 2);
120 if (E == StringRef::npos)
121 error("unclosed comment in a linker script");
122 S = S.substr(E + 2);
123 continue;
124 }
125 size_t Size = S.size();
126 S = S.ltrim();
127 if (S.size() == Size)
128 return S;
129 }
130}
131
132StringRef LinkerScript::next() {
133 if (Pos == Tokens.size())
134 error("unexpected EOF");
135 return Tokens[Pos++];
136}
137
138void LinkerScript::expect(StringRef Expect) {
139 StringRef Tok = next();
140 if (Tok != Expect)
141 error(Expect + " expected, but got " + Tok);
142}
143
Rui Ueyama52a15092015-10-11 03:28:42 +0000144void LinkerScript::addFile(StringRef S) {
Rui Ueyamaf03f3cc2015-10-13 00:09:21 +0000145 if (sys::path::is_absolute(S)) {
Rui Ueyama52a15092015-10-11 03:28:42 +0000146 Driver->addFile(S);
147 } else if (S.startswith("=")) {
148 if (Config->Sysroot.empty())
149 Driver->addFile(S.substr(1));
150 else
151 Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
152 } else if (S.startswith("-l")) {
153 Driver->addFile(searchLibrary(S.substr(2)));
154 } else {
155 std::string Path = findFromSearchPaths(S);
156 if (Path.empty())
157 error("Unable to find " + S);
158 Driver->addFile(Saver.save(Path));
159 }
160}
161
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000162void LinkerScript::readAsNeeded() {
163 expect("(");
Rui Ueyama35da9b62015-10-11 20:59:12 +0000164 bool Orig = Config->AsNeeded;
165 Config->AsNeeded = true;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000166 for (;;) {
167 StringRef Tok = next();
168 if (Tok == ")")
Rui Ueyama35da9b62015-10-11 20:59:12 +0000169 break;
Rui Ueyama52a15092015-10-11 03:28:42 +0000170 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000171 }
Rui Ueyama35da9b62015-10-11 20:59:12 +0000172 Config->AsNeeded = Orig;
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000173}
174
Denis Protivensky90c50992015-10-08 06:48:38 +0000175void LinkerScript::readEntry() {
176 // -e <symbol> takes predecence over ENTRY(<symbol>).
177 expect("(");
178 StringRef Tok = next();
179 if (Config->Entry.empty())
180 Config->Entry = Tok;
181 expect(")");
182}
183
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000184void LinkerScript::readGroup() {
185 expect("(");
186 for (;;) {
187 StringRef Tok = next();
188 if (Tok == ")")
189 return;
190 if (Tok == "AS_NEEDED") {
191 readAsNeeded();
192 continue;
193 }
Rui Ueyama52a15092015-10-11 03:28:42 +0000194 addFile(Tok);
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000195 }
196}
197
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000198void LinkerScript::readInclude() {
199 StringRef Tok = next();
200 auto MBOrErr = MemoryBuffer::getFile(Tok);
Rui Ueyama1c42afc2015-10-12 15:49:06 +0000201 error(MBOrErr, "cannot open " + Tok);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000202 std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000203 StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
204 std::vector<StringRef> V = tokenize(S);
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000205 Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
Rui Ueyama31aa1f82015-10-11 01:31:55 +0000206}
207
Rui Ueyamaee592822015-10-07 00:25:09 +0000208void LinkerScript::readOutput() {
209 // -o <file> takes predecence over OUTPUT(<file>).
210 expect("(");
211 StringRef Tok = next();
212 if (Config->OutputFile.empty())
213 Config->OutputFile = Tok;
214 expect(")");
215}
216
Davide Italiano9159ce92015-10-12 21:50:08 +0000217void LinkerScript::readOutputArch() {
218 // Error checking only for now.
219 expect("(");
220 next();
221 expect(")");
222}
223
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000224void LinkerScript::readOutputFormat() {
225 // Error checking only for now.
226 expect("(");
227 next();
Davide Italiano6836c612015-10-12 21:08:41 +0000228 StringRef Tok = next();
229 if (Tok == ")")
230 return;
231 if (Tok != ",")
232 error("unexpected token: " + Tok);
233 next();
234 expect(",");
235 next();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000236 expect(")");
237}
238
Davide Italiano68a39a62015-10-08 17:51:41 +0000239void LinkerScript::readSearchDir() {
240 expect("(");
Rui Ueyama52a15092015-10-11 03:28:42 +0000241 Config->SearchPaths.push_back(next());
Davide Italiano68a39a62015-10-08 17:51:41 +0000242 expect(")");
243}
244
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000245// Entry point. The other functions or classes are private to this file.
Rui Ueyamaa47ee682015-10-11 01:53:04 +0000246void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
247 LinkerScript(A, MB.getBuffer()).run();
Rui Ueyamaf7c5fbb2015-09-30 17:23:26 +0000248}