| //===- COFF/ModuleDef.cpp -------------------------------------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Windows-specific. |
| // A parser for the module-definition file (.def file). |
| // Parsed results are directly written to Config global variable. |
| // |
| // The format of module-definition files are described in this document: |
| // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Config.h" |
| #include "Error.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/Support/StringSaver.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <system_error> |
| |
| using namespace llvm; |
| |
| namespace lld { |
| namespace coff { |
| namespace { |
| |
| enum Kind { |
| Unknown, |
| Eof, |
| Identifier, |
| Comma, |
| Equal, |
| KwBase, |
| KwData, |
| KwExports, |
| KwHeapsize, |
| KwLibrary, |
| KwName, |
| KwNoname, |
| KwPrivate, |
| KwStacksize, |
| KwVersion, |
| }; |
| |
| struct Token { |
| explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {} |
| Kind K; |
| StringRef Value; |
| }; |
| |
| static bool isDecorated(StringRef Sym) { |
| return Sym.startswith("_") || Sym.startswith("@") || Sym.startswith("?"); |
| } |
| |
| class Lexer { |
| public: |
| explicit Lexer(StringRef S) : Buf(S) {} |
| |
| Token lex() { |
| Buf = Buf.trim(); |
| if (Buf.empty()) |
| return Token(Eof); |
| |
| switch (Buf[0]) { |
| case '\0': |
| return Token(Eof); |
| case ';': { |
| size_t End = Buf.find('\n'); |
| Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); |
| return lex(); |
| } |
| case '=': |
| Buf = Buf.drop_front(); |
| return Token(Equal, "="); |
| case ',': |
| Buf = Buf.drop_front(); |
| return Token(Comma, ","); |
| case '"': { |
| StringRef S; |
| std::tie(S, Buf) = Buf.substr(1).split('"'); |
| return Token(Identifier, S); |
| } |
| default: { |
| size_t End = Buf.find_first_of("=,\r\n \t\v"); |
| StringRef Word = Buf.substr(0, End); |
| Kind K = llvm::StringSwitch<Kind>(Word) |
| .Case("BASE", KwBase) |
| .Case("DATA", KwData) |
| .Case("EXPORTS", KwExports) |
| .Case("HEAPSIZE", KwHeapsize) |
| .Case("LIBRARY", KwLibrary) |
| .Case("NAME", KwName) |
| .Case("NONAME", KwNoname) |
| .Case("PRIVATE", KwPrivate) |
| .Case("STACKSIZE", KwStacksize) |
| .Case("VERSION", KwVersion) |
| .Default(Identifier); |
| Buf = (End == Buf.npos) ? "" : Buf.drop_front(End); |
| return Token(K, Word); |
| } |
| } |
| } |
| |
| private: |
| StringRef Buf; |
| }; |
| |
| class Parser { |
| public: |
| explicit Parser(StringRef S, StringSaver *A) : Lex(S), Alloc(A) {} |
| |
| void parse() { |
| do { |
| parseOne(); |
| } while (Tok.K != Eof); |
| } |
| |
| private: |
| void read() { |
| if (Stack.empty()) { |
| Tok = Lex.lex(); |
| return; |
| } |
| Tok = Stack.back(); |
| Stack.pop_back(); |
| } |
| |
| void readAsInt(uint64_t *I) { |
| read(); |
| if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I)) |
| error("integer expected"); |
| } |
| |
| void expect(Kind Expected, StringRef Msg) { |
| read(); |
| if (Tok.K != Expected) |
| error(Msg); |
| } |
| |
| void unget() { Stack.push_back(Tok); } |
| |
| void parseOne() { |
| read(); |
| switch (Tok.K) { |
| case Eof: |
| return; |
| case KwExports: |
| for (;;) { |
| read(); |
| if (Tok.K != Identifier) { |
| unget(); |
| return; |
| } |
| parseExport(); |
| } |
| case KwHeapsize: |
| parseNumbers(&Config->HeapReserve, &Config->HeapCommit); |
| return; |
| case KwLibrary: |
| parseName(&Config->OutputFile, &Config->ImageBase); |
| if (!StringRef(Config->OutputFile).endswith_lower(".dll")) |
| Config->OutputFile += ".dll"; |
| return; |
| case KwStacksize: |
| parseNumbers(&Config->StackReserve, &Config->StackCommit); |
| return; |
| case KwName: |
| parseName(&Config->OutputFile, &Config->ImageBase); |
| return; |
| case KwVersion: |
| parseVersion(&Config->MajorImageVersion, &Config->MinorImageVersion); |
| return; |
| default: |
| error(Twine("unknown directive: ") + Tok.Value); |
| } |
| } |
| |
| void parseExport() { |
| Export E; |
| E.Name = Tok.Value; |
| read(); |
| if (Tok.K == Equal) { |
| read(); |
| if (Tok.K != Identifier) |
| error(Twine("identifier expected, but got ") + Tok.Value); |
| E.ExtName = E.Name; |
| E.Name = Tok.Value; |
| } else { |
| unget(); |
| } |
| |
| if (Config->Machine == I386) { |
| if (!isDecorated(E.Name)) |
| E.Name = Alloc->save("_" + E.Name); |
| if (!E.ExtName.empty() && !isDecorated(E.ExtName)) |
| E.ExtName = Alloc->save("_" + E.ExtName); |
| } |
| |
| for (;;) { |
| read(); |
| if (Tok.K == Identifier && Tok.Value[0] == '@') { |
| Tok.Value.drop_front().getAsInteger(10, E.Ordinal); |
| read(); |
| if (Tok.K == KwNoname) { |
| E.Noname = true; |
| } else { |
| unget(); |
| } |
| continue; |
| } |
| if (Tok.K == KwData) { |
| E.Data = true; |
| continue; |
| } |
| if (Tok.K == KwPrivate) { |
| E.Private = true; |
| continue; |
| } |
| unget(); |
| Config->Exports.push_back(E); |
| return; |
| } |
| } |
| |
| // HEAPSIZE/STACKSIZE reserve[,commit] |
| void parseNumbers(uint64_t *Reserve, uint64_t *Commit) { |
| readAsInt(Reserve); |
| read(); |
| if (Tok.K != Comma) { |
| unget(); |
| Commit = nullptr; |
| return; |
| } |
| readAsInt(Commit); |
| } |
| |
| // NAME outputPath [BASE=address] |
| void parseName(std::string *Out, uint64_t *Baseaddr) { |
| read(); |
| if (Tok.K == Identifier) { |
| *Out = Tok.Value; |
| } else { |
| *Out = ""; |
| unget(); |
| return; |
| } |
| read(); |
| if (Tok.K == KwBase) { |
| expect(Equal, "'=' expected"); |
| readAsInt(Baseaddr); |
| } else { |
| unget(); |
| *Baseaddr = 0; |
| } |
| } |
| |
| // VERSION major[.minor] |
| void parseVersion(uint32_t *Major, uint32_t *Minor) { |
| read(); |
| if (Tok.K != Identifier) |
| error(Twine("identifier expected, but got ") + Tok.Value); |
| StringRef V1, V2; |
| std::tie(V1, V2) = Tok.Value.split('.'); |
| if (V1.getAsInteger(10, *Major)) |
| error(Twine("integer expected, but got ") + Tok.Value); |
| if (V2.empty()) |
| *Minor = 0; |
| else if (V2.getAsInteger(10, *Minor)) |
| error(Twine("integer expected, but got ") + Tok.Value); |
| } |
| |
| Lexer Lex; |
| Token Tok; |
| std::vector<Token> Stack; |
| StringSaver *Alloc; |
| }; |
| |
| } // anonymous namespace |
| |
| void parseModuleDefs(MemoryBufferRef MB, StringSaver *Alloc) { |
| Parser(MB.getBuffer(), Alloc).parse(); |
| } |
| |
| } // namespace coff |
| } // namespace lld |