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