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