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;
55 explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
60 static bool isDecorated(StringRef Sym, bool MingwDef) {
61 // In def files, the symbols can either be listed decorated or undecorated.
63 // - For cdecl symbols, only the undecorated form is allowed.
64 // - For fastcall and vectorcall symbols, both fully decorated or
65 // undecorated forms can be present.
66 // - For stdcall symbols in non-MinGW environments, the decorated form is
67 // fully decorated with leading underscore and trailing stack argument
68 // size - like "_Func@0".
69 // - In MinGW def files, a decorated stdcall symbol does not include the
70 // leading underscore though, like "Func@0".
72 // This function controls whether a leading underscore should be added to
73 // the given symbol name or not. For MinGW, treat a stdcall symbol name such
74 // as "Func@0" as undecorated, i.e. a leading underscore must be added.
75 // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
76 // as decorated, i.e. don't add any more leading underscores.
77 // We can't check for a leading underscore here, since function names
78 // themselves can start with an underscore, while a second one still needs
80 return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") ||
81 (!MingwDef && Sym.contains('@'));
84 static Error createError(const Twine &Err) {
85 return make_error<StringError>(StringRef(Err.str()),
86 object_error::parse_failed);
91 Lexer(StringRef S) : Buf(S) {}
102 size_t End = Buf.find('\n');
103 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
107 Buf = Buf.drop_front();
108 if (Buf.startswith("=")) {
109 Buf = Buf.drop_front();
110 return Token(EqualEqual, "==");
112 return Token(Equal, "=");
114 Buf = Buf.drop_front();
115 return Token(Comma, ",");
118 std::tie(S, Buf) = Buf.substr(1).split('"');
119 return Token(Identifier, S);
122 size_t End = Buf.find_first_of("=,;\r\n \t\v");
123 StringRef Word = Buf.substr(0, End);
124 Kind K = llvm::StringSwitch<Kind>(Word)
125 .Case("BASE", KwBase)
126 .Case("CONSTANT", KwConstant)
127 .Case("DATA", KwData)
128 .Case("EXPORTS", KwExports)
129 .Case("HEAPSIZE", KwHeapsize)
130 .Case("LIBRARY", KwLibrary)
131 .Case("NAME", KwName)
132 .Case("NONAME", KwNoname)
133 .Case("PRIVATE", KwPrivate)
134 .Case("STACKSIZE", KwStacksize)
135 .Case("VERSION", KwVersion)
136 .Default(Identifier);
137 Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
138 return Token(K, Word);
149 explicit Parser(StringRef S, MachineTypes M, bool B)
150 : Lex(S), Machine(M), MingwDef(B) {}
152 Expected<COFFModuleDefinition> parse() {
154 if (Error Err = parseOne())
155 return std::move(Err);
156 } while (Tok.K != Eof);
170 Error readAsInt(uint64_t *I) {
172 if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
173 return createError("integer expected");
174 return Error::success();
177 Error expect(Kind Expected, StringRef Msg) {
179 if (Tok.K != Expected)
180 return createError(Msg);
181 return Error::success();
184 void unget() { Stack.push_back(Tok); }
190 return Error::success();
194 if (Tok.K != Identifier) {
196 return Error::success();
198 if (Error Err = parseExport())
202 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
204 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
207 bool IsDll = Tok.K == KwLibrary; // Check before parseName.
209 if (Error Err = parseName(&Name, &Info.ImageBase))
212 Info.ImportName = Name;
214 // Set the output file, but don't override /out if it was already passed.
215 if (Info.OutputFile.empty()) {
216 Info.OutputFile = Name;
217 // Append the appropriate file extension if not already present.
218 if (!sys::path::has_extension(Name))
219 Info.OutputFile += IsDll ? ".dll" : ".exe";
222 return Error::success();
225 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
227 return createError("unknown directive: " + Tok.Value);
231 Error parseExport() {
235 if (Tok.K == Equal) {
237 if (Tok.K != Identifier)
238 return createError("identifier expected, but got " + Tok.Value);
245 if (Machine == IMAGE_FILE_MACHINE_I386) {
246 if (!isDecorated(E.Name, MingwDef))
247 E.Name = (std::string("_").append(E.Name));
248 if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
249 E.ExtName = (std::string("_").append(E.ExtName));
254 if (Tok.K == Identifier && Tok.Value[0] == '@') {
255 if (Tok.Value == "@") {
258 Tok.Value.getAsInteger(10, E.Ordinal);
259 } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) {
260 // "foo \n @bar" - Not an ordinal modifier at all, but the next
261 // export (fastcall decorated) - complete the current one.
263 Info.Exports.push_back(E);
264 return Error::success();
268 if (Tok.K == KwNoname) {
275 if (Tok.K == KwData) {
279 if (Tok.K == KwConstant) {
283 if (Tok.K == KwPrivate) {
287 if (Tok.K == EqualEqual) {
289 E.AliasTarget = Tok.Value;
290 if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
291 E.AliasTarget = std::string("_").append(E.AliasTarget);
295 Info.Exports.push_back(E);
296 return Error::success();
300 // HEAPSIZE/STACKSIZE reserve[,commit]
301 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
302 if (Error Err = readAsInt(Reserve))
305 if (Tok.K != Comma) {
308 return Error::success();
310 if (Error Err = readAsInt(Commit))
312 return Error::success();
315 // NAME outputPath [BASE=address]
316 Error parseName(std::string *Out, uint64_t *Baseaddr) {
318 if (Tok.K == Identifier) {
323 return Error::success();
326 if (Tok.K == KwBase) {
327 if (Error Err = expect(Equal, "'=' expected"))
329 if (Error Err = readAsInt(Baseaddr))
335 return Error::success();
338 // VERSION major[.minor]
339 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
341 if (Tok.K != Identifier)
342 return createError("identifier expected, but got " + Tok.Value);
344 std::tie(V1, V2) = Tok.Value.split('.');
345 if (V1.getAsInteger(10, *Major))
346 return createError("integer expected, but got " + Tok.Value);
349 else if (V2.getAsInteger(10, *Minor))
350 return createError("integer expected, but got " + Tok.Value);
351 return Error::success();
356 std::vector<Token> Stack;
357 MachineTypes Machine;
358 COFFModuleDefinition Info;
362 Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
363 MachineTypes Machine,
365 return Parser(MB.getBuffer(), Machine, MingwDef).parse();
368 } // namespace object