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 atEOF() { return Tokens.size() == Pos; }
40   void expect(StringRef Expect);
41 
42   void addFile(StringRef Path);
43 
44   void readAsNeeded();
45   void readEntry();
46   void readGroup();
47   void readInclude();
48   void readOutput();
49   void readOutputArch();
50   void readOutputFormat();
51   void readSearchDir();
52 
53   StringSaver Saver;
54   std::vector<StringRef> Tokens;
55   size_t Pos = 0;
56 };
57 }
58 
59 void LinkerScript::run() {
60   while (!atEOF()) {
61     StringRef Tok = next();
62     if (Tok == ";")
63       continue;
64     if (Tok == "ENTRY") {
65       readEntry();
66     } else if (Tok == "GROUP" || Tok == "INPUT") {
67       readGroup();
68     } else if (Tok == "INCLUDE") {
69       readInclude();
70     } else if (Tok == "OUTPUT") {
71       readOutput();
72     } else if (Tok == "OUTPUT_ARCH") {
73       readOutputArch();
74     } else if (Tok == "OUTPUT_FORMAT") {
75       readOutputFormat();
76     } else if (Tok == "SEARCH_DIR") {
77       readSearchDir();
78     } else {
79       error("unknown directive: " + Tok);
80     }
81   }
82 }
83 
84 // Split S into linker script tokens.
85 std::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.
116 StringRef 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 
132 StringRef LinkerScript::next() {
133   if (Pos == Tokens.size())
134     error("unexpected EOF");
135   return Tokens[Pos++];
136 }
137 
138 void LinkerScript::expect(StringRef Expect) {
139   StringRef Tok = next();
140   if (Tok != Expect)
141     error(Expect + " expected, but got " + Tok);
142 }
143 
144 void LinkerScript::addFile(StringRef S) {
145   if (sys::path::is_absolute(S)) {
146     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 
162 void LinkerScript::readAsNeeded() {
163   expect("(");
164   bool Orig = Config->AsNeeded;
165   Config->AsNeeded = true;
166   for (;;) {
167     StringRef Tok = next();
168     if (Tok == ")")
169       break;
170     addFile(Tok);
171   }
172   Config->AsNeeded = Orig;
173 }
174 
175 void 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 
184 void 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     }
194     addFile(Tok);
195   }
196 }
197 
198 void LinkerScript::readInclude() {
199   StringRef Tok = next();
200   auto MBOrErr = MemoryBuffer::getFile(Tok);
201   error(MBOrErr, "cannot open " + Tok);
202   std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
203   StringRef S = Saver.save(MB->getMemBufferRef().getBuffer());
204   std::vector<StringRef> V = tokenize(S);
205   Tokens.insert(Tokens.begin() + Pos, V.begin(), V.end());
206 }
207 
208 void 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 
217 void LinkerScript::readOutputArch() {
218   // Error checking only for now.
219   expect("(");
220   next();
221   expect(")");
222 }
223 
224 void LinkerScript::readOutputFormat() {
225   // Error checking only for now.
226   expect("(");
227   next();
228   StringRef Tok = next();
229   if (Tok == ")")
230    return;
231   if (Tok != ",")
232     error("unexpected token: " + Tok);
233   next();
234   expect(",");
235   next();
236   expect(")");
237 }
238 
239 void LinkerScript::readSearchDir() {
240   expect("(");
241   Config->SearchPaths.push_back(next());
242   expect(")");
243 }
244 
245 // Entry point. The other functions or classes are private to this file.
246 void lld::elf2::readLinkerScript(BumpPtrAllocator *A, MemoryBufferRef MB) {
247   LinkerScript(A, MB.getBuffer()).run();
248 }
249