1 //===- 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 Driver 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"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/StringSaver.h"
23 
24 using namespace llvm;
25 using namespace lld;
26 using namespace lld::elf2;
27 
28 namespace {
29 class LinkerScript {
30 public:
31   LinkerScript(BumpPtrAllocator *A, StringRef S)
32       : Saver(*A), Tokens(tokenize(S)) {}
33   void run();
34 
35 private:
36   static std::vector<StringRef> tokenize(StringRef S);
37   static StringRef skipSpace(StringRef S);
38   StringRef next();
39   bool skip(StringRef Tok);
40   bool atEOF() { return Tokens.size() == Pos; }
41   void expect(StringRef Expect);
42 
43   void addFile(StringRef Path);
44 
45   void readAsNeeded();
46   void readEntry();
47   void readExtern();
48   void readGroup();
49   void readInclude();
50   void readOutput();
51   void readOutputArch();
52   void readOutputFormat();
53   void readSearchDir();
54   void readSections();
55 
56   void readOutputSectionDescription();
57 
58   StringSaver Saver;
59   std::vector<StringRef> Tokens;
60   size_t Pos = 0;
61 };
62 }
63 
64 void LinkerScript::run() {
65   while (!atEOF()) {
66     StringRef Tok = next();
67     if (Tok == ";")
68       continue;
69     if (Tok == "ENTRY") {
70       readEntry();
71     } else if (Tok == "EXTERN") {
72       readExtern();
73     } else if (Tok == "GROUP" || Tok == "INPUT") {
74       readGroup();
75     } else if (Tok == "INCLUDE") {
76       readInclude();
77     } else if (Tok == "OUTPUT") {
78       readOutput();
79     } else if (Tok == "OUTPUT_ARCH") {
80       readOutputArch();
81     } else if (Tok == "OUTPUT_FORMAT") {
82       readOutputFormat();
83     } else if (Tok == "SEARCH_DIR") {
84       readSearchDir();
85     } else if (Tok == "SECTIONS") {
86       readSections();
87     } else {
88       error("unknown directive: " + Tok);
89     }
90   }
91 }
92 
93 // Split S into linker script tokens.
94 std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
95   std::vector<StringRef> Ret;
96   for (;;) {
97     S = skipSpace(S);
98     if (S.empty())
99       return Ret;
100 
101     // Quoted token
102     if (S.startswith("\"")) {
103       size_t E = S.find("\"", 1);
104       if (E == StringRef::npos)
105         error("unclosed quote");
106       Ret.push_back(S.substr(1, E));
107       S = S.substr(E + 1);
108       continue;
109     }
110 
111     // Unquoted token
112     size_t Pos = S.find_first_not_of(
113         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
114         "0123456789_.$/\\~=+[]*?-:");
115     // A character that cannot start a word (which is usually a
116     // punctuation) forms a single character token.
117     if (Pos == 0)
118       Pos = 1;
119     Ret.push_back(S.substr(0, Pos));
120     S = S.substr(Pos);
121   }
122 }
123 
124 // Skip leading whitespace characters or /**/-style comments.
125 StringRef LinkerScript::skipSpace(StringRef S) {
126   for (;;) {
127     if (S.startswith("/*")) {
128       size_t E = S.find("*/", 2);
129       if (E == StringRef::npos)
130         error("unclosed comment in a linker script");
131       S = S.substr(E + 2);
132       continue;
133     }
134     size_t Size = S.size();
135     S = S.ltrim();
136     if (S.size() == Size)
137       return S;
138   }
139 }
140 
141 StringRef LinkerScript::next() {
142   if (atEOF())
143     error("unexpected EOF");
144   return Tokens[Pos++];
145 }
146 
147 bool LinkerScript::skip(StringRef Tok) {
148   if (atEOF())
149     error("unexpected EOF");
150   if (Tok != Tokens[Pos])
151     return false;
152   ++Pos;
153   return true;
154 }
155 
156 void LinkerScript::expect(StringRef Expect) {
157   StringRef Tok = next();
158   if (Tok != Expect)
159     error(Expect + " expected, but got " + Tok);
160 }
161 
162 void LinkerScript::addFile(StringRef S) {
163   if (sys::path::is_absolute(S)) {
164     Driver->addFile(S);
165   } else if (S.startswith("=")) {
166     if (Config->Sysroot.empty())
167       Driver->addFile(S.substr(1));
168     else
169       Driver->addFile(Saver.save(Config->Sysroot + "/" + S.substr(1)));
170   } else if (S.startswith("-l")) {
171     Driver->addFile(searchLibrary(S.substr(2)));
172   } else {
173     std::string Path = findFromSearchPaths(S);
174     if (Path.empty())
175       error("Unable to find " + S);
176     Driver->addFile(Saver.save(Path));
177   }
178 }
179 
180 void LinkerScript::readAsNeeded() {
181   expect("(");
182   bool Orig = Config->AsNeeded;
183   Config->AsNeeded = true;
184   for (;;) {
185     StringRef Tok = next();
186     if (Tok == ")")
187       break;
188     addFile(Tok);
189   }
190   Config->AsNeeded = Orig;
191 }
192 
193 void LinkerScript::readEntry() {
194   // -e <symbol> takes predecence over ENTRY(<symbol>).
195   expect("(");
196   StringRef Tok = next();
197   if (Config->Entry.empty())
198     Config->Entry = Tok;
199   expect(")");
200 }
201 
202 void LinkerScript::readExtern() {
203   expect("(");
204   for (;;) {
205     StringRef Tok = next();
206     if (Tok == ")")
207       return;
208     Config->Undefined.push_back(Tok);
209   }
210 }
211 
212 void LinkerScript::readGroup() {
213   expect("(");
214   for (;;) {
215     StringRef Tok = next();
216     if (Tok == ")")
217       return;
218     if (Tok == "AS_NEEDED") {
219       readAsNeeded();
220       continue;
221     }
222     addFile(Tok);
223   }
224 }
225 
226 void LinkerScript::readInclude() {
227   StringRef Tok = next();
228   auto MBOrErr = MemoryBuffer::getFile(Tok);
229   error(MBOrErr, "cannot open " + Tok);
230   std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
231   StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
232   std::vector<StringRef> V = tokenize(S);
233   Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
234 }
235 
236 void LinkerScript::readOutput() {
237   // -o <file> takes predecence over OUTPUT(<file>).
238   expect("(");
239   StringRef Tok = next();
240   if (Config->OutputFile.empty())
241     Config->OutputFile = Tok;
242   expect(")");
243 }
244 
245 void LinkerScript::readOutputArch() {
246   // Error checking only for now.
247   expect("(");
248   next();
249   expect(")");
250 }
251 
252 void LinkerScript::readOutputFormat() {
253   // Error checking only for now.
254   expect("(");
255   next();
256   StringRef Tok = next();
257   if (Tok == ")")
258    return;
259   if (Tok != ",")
260     error("unexpected token: " + Tok);
261   next();
262   expect(",");
263   next();
264   expect(")");
265 }
266 
267 void LinkerScript::readSearchDir() {
268   expect("(");
269   Config->SearchPaths.push_back(next());
270   expect(")");
271 }
272 
273 void LinkerScript::readSections() {
274   expect("{");
275   while (!skip("}"))
276     readOutputSectionDescription();
277 }
278 
279 void LinkerScript::readOutputSectionDescription() {
280   StringRef Name = next();
281   std::vector<StringRef> &InputSections = Config->OutputSections[Name];
282 
283   expect(":");
284   expect("{");
285   while (!skip("}")) {
286     next(); // Skip input file name.
287     expect("(");
288     while (!skip(")"))
289       InputSections.push_back(next());
290   }
291 }
292 
293 // Entry point. The other functions or classes are private to this file.
294 void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
295   LinkerScript(A, MB.getBuffer()).run();
296 }
297