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 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"
21 
22 using namespace llvm;
23 using namespace lld;
24 using namespace lld::elf2;
25 
26 namespace {
27 class LinkerScript {
28 public:
29   LinkerScript(SymbolTable *T, StringRef S) : Symtab(T), Tokens(tokenize(S)) {}
30   void run();
31 
32 private:
33   static std::vector<StringRef> tokenize(StringRef S);
34   static StringRef skipSpace(StringRef S);
35   StringRef next();
36   bool atEOF() { return Tokens.size() == Pos; }
37   void expect(StringRef Expect);
38 
39   void readAsNeeded();
40   void readGroup();
41   void readOutputFormat();
42 
43   SymbolTable *Symtab;
44   std::vector<StringRef> Tokens;
45   size_t Pos = 0;
46 };
47 }
48 
49 void LinkerScript::run() {
50   while (!atEOF()) {
51     StringRef Tok = next();
52     if (Tok == "GROUP") {
53       readGroup();
54     } else if (Tok == "OUTPUT_FORMAT") {
55       readOutputFormat();
56     } else {
57       error("unknown directive: " + Tok);
58     }
59   }
60 }
61 
62 // Split S into linker script tokens.
63 std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
64   std::vector<StringRef> Ret;
65   for (;;) {
66     S = skipSpace(S);
67     if (S.empty())
68       return Ret;
69 
70     // Quoted token
71     if (S.startswith("\"")) {
72       size_t E = S.find("\"", 1);
73       if (E == StringRef::npos)
74         error("unclosed quote");
75       Ret.push_back(S.substr(1, E));
76       S = S.substr(E + 1);
77       continue;
78     }
79 
80     // Unquoted token
81     size_t Pos = S.find_first_not_of(
82         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
83         "0123456789_.$/\\~=+[]*?-:");
84     // A character that cannot start a word (which is usually a
85     // punctuation) forms a single character token.
86     if (Pos == 0)
87       Pos = 1;
88     Ret.push_back(S.substr(0, Pos));
89     S = S.substr(Pos);
90   }
91 }
92 
93 // Skip leading whitespace characters or /**/-style comments.
94 StringRef LinkerScript::skipSpace(StringRef S) {
95   for (;;) {
96     if (S.startswith("/*")) {
97       size_t E = S.find("*/", 2);
98       if (E == StringRef::npos)
99         error("unclosed comment in a linker script");
100       S = S.substr(E + 2);
101       continue;
102     }
103     size_t Size = S.size();
104     S = S.ltrim();
105     if (S.size() == Size)
106       return S;
107   }
108 }
109 
110 StringRef LinkerScript::next() {
111   if (Pos == Tokens.size())
112     error("unexpected EOF");
113   return Tokens[Pos++];
114 }
115 
116 void LinkerScript::expect(StringRef Expect) {
117   StringRef Tok = next();
118   if (Tok != Expect)
119     error(Expect + " expected, but got " + Tok);
120 }
121 
122 void LinkerScript::readAsNeeded() {
123   expect("(");
124   for (;;) {
125     StringRef Tok = next();
126     if (Tok == ")")
127       return;
128     Symtab->addFile(createFile(openFile(Tok)));
129   }
130 }
131 
132 void LinkerScript::readGroup() {
133   expect("(");
134   for (;;) {
135     StringRef Tok = next();
136     if (Tok == ")")
137       return;
138     if (Tok == "AS_NEEDED") {
139       readAsNeeded();
140       continue;
141     }
142     Symtab->addFile(createFile(openFile(Tok)));
143   }
144 }
145 
146 void LinkerScript::readOutputFormat() {
147   // Error checking only for now.
148   expect("(");
149   next();
150   expect(")");
151 }
152 
153 // Entry point. The other functions or classes are private to this file.
154 void lld::elf2::readLinkerScript(SymbolTable *Symtab, MemoryBufferRef MB) {
155   LinkerScript(Symtab, MB.getBuffer()).run();
156 }
157