]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lld/COFF/ModuleDef.cpp
Update compiler-rt to 3.9.0 release, and update the build glue for
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lld / COFF / ModuleDef.cpp
1 //===- COFF/ModuleDef.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 // Windows-specific.
11 // A parser for the module-definition file (.def file).
12 // Parsed results are directly written to Config global variable.
13 //
14 // The format of module-definition files are described in this document:
15 // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
16 //
17 //===----------------------------------------------------------------------===//
18
19 #include "Config.h"
20 #include "Error.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/ADT/StringSwitch.h"
23 #include "llvm/Support/StringSaver.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <system_error>
26
27 using namespace llvm;
28
29 namespace lld {
30 namespace coff {
31 namespace {
32
33 enum Kind {
34   Unknown,
35   Eof,
36   Identifier,
37   Comma,
38   Equal,
39   KwBase,
40   KwData,
41   KwExports,
42   KwHeapsize,
43   KwLibrary,
44   KwName,
45   KwNoname,
46   KwPrivate,
47   KwStacksize,
48   KwVersion,
49 };
50
51 struct Token {
52   explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
53   Kind K;
54   StringRef Value;
55 };
56
57 static bool isDecorated(StringRef Sym) {
58   return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?");
59 }
60
61 class Lexer {
62 public:
63   explicit Lexer(StringRef S) : Buf(S) {}
64
65   Token lex() {
66     Buf = Buf.trim();
67     if (Buf.empty())
68       return Token(Eof);
69
70     switch (Buf[0]) {
71     case '\0':
72       return Token(Eof);
73     case ';': {
74       size_t End = Buf.find('\n');
75       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
76       return lex();
77     }
78     case '=':
79       Buf = Buf.drop_front();
80       return Token(Equal, "=");
81     case ',':
82       Buf = Buf.drop_front();
83       return Token(Comma, ",");
84     case '"': {
85       StringRef S;
86       std::tie(S, Buf) = Buf.substr(1).split('"');
87       return Token(Identifier, S);
88     }
89     default: {
90       size_t End = Buf.find_first_of("=,\r\n \t\v");
91       StringRef Word = Buf.substr(0, End);
92       Kind K = llvm::StringSwitch<Kind>(Word)
93                    .Case("BASE", KwBase)
94                    .Case("DATA", KwData)
95                    .Case("EXPORTS", KwExports)
96                    .Case("HEAPSIZE", KwHeapsize)
97                    .Case("LIBRARY", KwLibrary)
98                    .Case("NAME", KwName)
99                    .Case("NONAME", KwNoname)
100                    .Case("PRIVATE", KwPrivate)
101                    .Case("STACKSIZE", KwStacksize)
102                    .Case("VERSION", KwVersion)
103                    .Default(Identifier);
104       Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
105       return Token(K, Word);
106     }
107     }
108   }
109
110 private:
111   StringRef Buf;
112 };
113
114 class Parser {
115 public:
116   explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {}
117
118   void parse() {
119     do {
120       parseOne();
121     } while (Tok.K != Eof);
122   }
123
124 private:
125   void read() {
126     if (Stack.empty()) {
127       Tok = Lex.lex();
128       return;
129     }
130     Tok = Stack.back();
131     Stack.pop_back();
132   }
133
134   void readAsInt(uint64_t *I) {
135     read();
136     if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
137       fatal("integer expected");
138   }
139
140   void expect(Kind Expected, StringRef Msg) {
141     read();
142     if (Tok.K != Expected)
143       fatal(Msg);
144   }
145
146   void unget() { Stack.push_back(Tok); }
147
148   void parseOne() {
149     read();
150     switch (Tok.K) {
151     case Eof:
152       return;
153     case KwExports:
154       for (;;) {
155         read();
156         if (Tok.K != Identifier) {
157           unget();
158           return;
159         }
160         parseExport();
161       }
162     case KwHeapsize:
163       parseNumbers(&Config->HeapReserve, &Config->HeapCommit);
164       return;
165     case KwLibrary:
166       parseName(&Config->OutputFile, &Config->ImageBase);
167       if (!StringRef(Config->OutputFile).endswith_lower(".dll"))
168         Config->OutputFile += ".dll";
169       return;
170     case KwStacksize:
171       parseNumbers(&Config->StackReserve, &Config->StackCommit);
172       return;
173     case KwName:
174       parseName(&Config->OutputFile, &Config->ImageBase);
175       return;
176     case KwVersion:
177       parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion);
178       return;
179     default:
180       fatal("unknown directive: " + Tok.Value);
181     }
182   }
183
184   void parseExport() {
185     Export E;
186     E.Name = Tok.Value;
187     read();
188     if (Tok.K == Equal) {
189       read();
190       if (Tok.K != Identifier)
191         fatal("identifier expected, but got " + Tok.Value);
192       E.ExtName = E.Name;
193       E.Name = Tok.Value;
194     } else {
195       unget();
196     }
197
198     if (Config->Machine == I386) {
199       if (!isDecorated(E.Name))
200         E.Name = Alloc->save("_" + E.Name);
201       if (!E.ExtName.empty() && !isDecorated(E.ExtName))
202         E.ExtName = Alloc->save("_" + E.ExtName);
203     }
204
205     for (;;) {
206       read();
207       if (Tok.K == Identifier && Tok.Value[0] == '@') {
208         Tok.Value.drop_front().getAsInteger(10, E.Ordinal);
209         read();
210         if (Tok.K == KwNoname) {
211           E.Noname = true;
212         } else {
213           unget();
214         }
215         continue;
216       }
217       if (Tok.K == KwData) {
218         E.Data = true;
219         continue;
220       }
221       if (Tok.K == KwPrivate) {
222         E.Private = true;
223         continue;
224       }
225       unget();
226       Config->Exports.push_back(E);
227       return;
228     }
229   }
230
231   // HEAPSIZE/STACKSIZE reserve[,commit]
232   void parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
233     readAsInt(Reserve);
234     read();
235     if (Tok.K != Comma) {
236       unget();
237       Commit = nullptr;
238       return;
239     }
240     readAsInt(Commit);
241   }
242
243   // NAME outputPath [BASE=address]
244   void parseName(std::string *Out, uint64_t *Baseaddr) {
245     read();
246     if (Tok.K == Identifier) {
247       *Out = Tok.Value;
248     } else {
249       *Out = "";
250       unget();
251       return;
252     }
253     read();
254     if (Tok.K == KwBase) {
255       expect(Equal, "'=' expected");
256       readAsInt(Baseaddr);
257     } else {
258       unget();
259       *Baseaddr = 0;
260     }
261   }
262
263   // VERSION major[.minor]
264   void parseVersion(uint32_t *Major, uint32_t *Minor) {
265     read();
266     if (Tok.K != Identifier)
267       fatal("identifier expected, but got " + Tok.Value);
268     StringRef V1, V2;
269     std::tie(V1, V2) = Tok.Value.split('.');
270     if (V1.getAsInteger(10, *Major))
271       fatal("integer expected, but got " + Tok.Value);
272     if (V2.empty())
273       *Minor = 0;
274     else if (V2.getAsInteger(10, *Minor))
275       fatal("integer expected, but got " + Tok.Value);
276   }
277
278   Lexer Lex;
279   Token Tok;
280   std::vector<Token> Stack;
281   StringSaver *Alloc;
282 };
283
284 } // anonymous namespace
285
286 void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) {
287   Parser(MB.getBuffer(), Alloc).parse();
288 }
289
290 } // namespace coff
291 } // namespace lld