1 //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 // A parser for the module-definition file (.def file).
13 // The format of module-definition files are described in this document:
14 // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
16 //===----------------------------------------------------------------------===//
18 #include "llvm/Object/COFFModuleDefinition.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/COFFImportFile.h"
23 #include "llvm/Object/Error.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/raw_ostream.h"
28 using namespace llvm::COFF;
54 explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
59 static bool isDecorated(StringRef Sym, bool MingwDef) {
60 // In def files, the symbols can either be listed decorated or undecorated.
62 // - For cdecl symbols, only the undecorated form is allowed.
63 // - For fastcall and vectorcall symbols, both fully decorated or
64 // undecorated forms can be present.
65 // - For stdcall symbols in non-MinGW environments, the decorated form is
66 // fully decorated with leading underscore and trailing stack argument
67 // size - like "_Func@0".
68 // - In MinGW def files, a decorated stdcall symbol does not include the
69 // leading underscore though, like "Func@0".
71 // This function controls whether a leading underscore should be added to
72 // the given symbol name or not. For MinGW, treat a stdcall symbol name such
73 // as "Func@0" as undecorated, i.e. a leading underscore must be added.
74 // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
75 // as decorated, i.e. don't add any more leading underscores.
76 // We can't check for a leading underscore here, since function names
77 // themselves can start with an underscore, while a second one still needs
79 return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
80 (!MingwDef && Sym.contains('@'));
83 static Error createError(const Twine &Err) {
84 return make_error<StringError>(StringRef(Err.str()),
85 object_error::parse_failed);
90 Lexer(StringRef S) : Buf(S) {}
101 size_t End = Buf.find('\n');
102 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
106 Buf = Buf.drop_front();
107 // GNU dlltool accepts both = and ==.
108 if (Buf.startswith("="))
109 Buf = Buf.drop_front();
110 return Token(Equal, "=");
112 Buf = Buf.drop_front();
113 return Token(Comma, ",");
116 std::tie(S, Buf) = Buf.substr(1).split('"');
117 return Token(Identifier, S);
120 size_t End = Buf.find_first_of("=,;\r\n \t\v");
121 StringRef Word = Buf.substr(0, End);
122 Kind K = llvm::StringSwitch<Kind>(Word)
123 .Case("BASE", KwBase)
124 .Case("CONSTANT", KwConstant)
125 .Case("DATA", KwData)
126 .Case("EXPORTS", KwExports)
127 .Case("HEAPSIZE", KwHeapsize)
128 .Case("LIBRARY", KwLibrary)
129 .Case("NAME", KwName)
130 .Case("NONAME", KwNoname)
131 .Case("PRIVATE", KwPrivate)
132 .Case("STACKSIZE", KwStacksize)
133 .Case("VERSION", KwVersion)
134 .Default(Identifier);
135 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
136 return Token(K, Word);
147 explicit Parser(StringRef S, MachineTypes M, bool B)
148 : Lex(S), Machine(M), MingwDef(B) {}
150 Expected<COFFModuleDefinition> parse() {
152 if (Error Err = parseOne())
153 return std::move(Err);
154 } while (Tok.K != Eof);
168 Error readAsInt(uint64_t *I) {
170 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
171 return createError("integer expected");
172 return Error::success();
175 Error expect(Kind Expected, StringRef Msg) {
177 if (Tok.K != Expected)
178 return createError(Msg);
179 return Error::success();
182 void unget() { Stack.push_back(Tok); }
188 return Error::success();
192 if (Tok.K != Identifier) {
194 return Error::success();
196 if (Error Err = parseExport())
200 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
202 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
205 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
207 if (Error Err = parseName(&Name, &Info.ImageBase))
210 Info.ImportName = Name;
212 // Set the output file, but don't override /out if it was already passed.
213 if (Info.OutputFile.empty()) {
214 Info.OutputFile = Name;
215 // Append the appropriate file extension if not already present.
216 if (!sys::path::has_extension(Name))
217 Info.OutputFile += IsDll ? ".dll" : ".exe";
220 return Error::success();
223 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
225 return createError("unknown directive: " + Tok.Value);
229 Error parseExport() {
233 if (Tok.K == Equal) {
235 if (Tok.K != Identifier)
236 return createError("identifier expected, but got " + Tok.Value);
243 if (Machine == IMAGE_FILE_MACHINE_I386) {
244 if (!isDecorated(E.Name, MingwDef))
245 E.Name = (std::string("_").append(E.Name));
246 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
247 E.ExtName = (std::string("_").append(E.ExtName));
252 if (Tok.K == Identifier && Tok.Value[0] == '@') {
253 if (Tok.Value == "@") {
256 Tok.Value.getAsInteger(10, E.Ordinal);
257 } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
258 // "foo \n @bar" - Not an ordinal modifier at all, but the next
259 // export (fastcall decorated) - complete the current one.
261 Info.Exports.push_back(E);
262 return Error::success();
266 if (Tok.K == KwNoname) {
273 if (Tok.K == KwData) {
277 if (Tok.K == KwConstant) {
281 if (Tok.K == KwPrivate) {
286 Info.Exports.push_back(E);
287 return Error::success();
291 // HEAPSIZE/STACKSIZE reserve[,commit]
292 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
293 if (Error Err = readAsInt(Reserve))
296 if (Tok.K != Comma) {
299 return Error::success();
301 if (Error Err = readAsInt(Commit))
303 return Error::success();
306 // NAME outputPath [BASE=address]
307 Error parseName(std::string *Out, uint64_t *Baseaddr) {
309 if (Tok.K == Identifier) {
314 return Error::success();
317 if (Tok.K == KwBase) {
318 if (Error Err = expect(Equal, "'=' expected"))
320 if (Error Err = readAsInt(Baseaddr))
326 return Error::success();
329 // VERSION major[.minor]
330 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
332 if (Tok.K != Identifier)
333 return createError("identifier expected, but got " + Tok.Value);
335 std::tie(V1, V2) = Tok.Value.split('.');
336 if (V1.getAsInteger(10, *Major))
337 return createError("integer expected, but got " + Tok.Value);
340 else if (V2.getAsInteger(10, *Minor))
341 return createError("integer expected, but got " + Tok.Value);
342 return Error::success();
347 std::vector<Token> Stack;
348 MachineTypes Machine;
349 COFFModuleDefinition Info;
353 Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
354 MachineTypes Machine,
356 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
359 } // namespace object