1 //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 // A parser for the module-definition file (.def file).
12 // The format of module-definition files are described in this document:
13 // https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
15 //===----------------------------------------------------------------------===//
17 #include "llvm/Object/COFFModuleDefinition.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/StringSwitch.h"
20 #include "llvm/Object/COFF.h"
21 #include "llvm/Object/COFFImportFile.h"
22 #include "llvm/Object/Error.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/raw_ostream.h"
27 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 if (Buf
.startswith("=")) {
108 Buf
= Buf
.drop_front();
109 return Token(EqualEqual
, "==");
111 return Token(Equal
, "=");
113 Buf
= Buf
.drop_front();
114 return Token(Comma
, ",");
117 std::tie(S
, Buf
) = Buf
.substr(1).split('"');
118 return Token(Identifier
, S
);
121 size_t End
= Buf
.find_first_of("=,;\r\n \t\v");
122 StringRef Word
= Buf
.substr(0, End
);
123 Kind K
= llvm::StringSwitch
<Kind
>(Word
)
124 .Case("BASE", KwBase
)
125 .Case("CONSTANT", KwConstant
)
126 .Case("DATA", KwData
)
127 .Case("EXPORTS", KwExports
)
128 .Case("HEAPSIZE", KwHeapsize
)
129 .Case("LIBRARY", KwLibrary
)
130 .Case("NAME", KwName
)
131 .Case("NONAME", KwNoname
)
132 .Case("PRIVATE", KwPrivate
)
133 .Case("STACKSIZE", KwStacksize
)
134 .Case("VERSION", KwVersion
)
135 .Default(Identifier
);
136 Buf
= (End
== Buf
.npos
) ? "" : Buf
.drop_front(End
);
137 return Token(K
, Word
);
148 explicit Parser(StringRef S
, MachineTypes M
, bool B
)
149 : Lex(S
), Machine(M
), MingwDef(B
) {}
151 Expected
<COFFModuleDefinition
> parse() {
153 if (Error Err
= parseOne())
154 return std::move(Err
);
155 } while (Tok
.K
!= Eof
);
169 Error
readAsInt(uint64_t *I
) {
171 if (Tok
.K
!= Identifier
|| Tok
.Value
.getAsInteger(10, *I
))
172 return createError("integer expected");
173 return Error::success();
176 Error
expect(Kind Expected
, StringRef Msg
) {
178 if (Tok
.K
!= Expected
)
179 return createError(Msg
);
180 return Error::success();
183 void unget() { Stack
.push_back(Tok
); }
189 return Error::success();
193 if (Tok
.K
!= Identifier
) {
195 return Error::success();
197 if (Error Err
= parseExport())
201 return parseNumbers(&Info
.HeapReserve
, &Info
.HeapCommit
);
203 return parseNumbers(&Info
.StackReserve
, &Info
.StackCommit
);
206 bool IsDll
= Tok
.K
== KwLibrary
; // Check before parseName.
208 if (Error Err
= parseName(&Name
, &Info
.ImageBase
))
211 Info
.ImportName
= Name
;
213 // Set the output file, but don't override /out if it was already passed.
214 if (Info
.OutputFile
.empty()) {
215 Info
.OutputFile
= Name
;
216 // Append the appropriate file extension if not already present.
217 if (!sys::path::has_extension(Name
))
218 Info
.OutputFile
+= IsDll
? ".dll" : ".exe";
221 return Error::success();
224 return parseVersion(&Info
.MajorImageVersion
, &Info
.MinorImageVersion
);
226 return createError("unknown directive: " + Tok
.Value
);
230 Error
parseExport() {
234 if (Tok
.K
== Equal
) {
236 if (Tok
.K
!= Identifier
)
237 return createError("identifier expected, but got " + Tok
.Value
);
244 if (Machine
== IMAGE_FILE_MACHINE_I386
) {
245 if (!isDecorated(E
.Name
, MingwDef
))
246 E
.Name
= (std::string("_").append(E
.Name
));
247 if (!E
.ExtName
.empty() && !isDecorated(E
.ExtName
, MingwDef
))
248 E
.ExtName
= (std::string("_").append(E
.ExtName
));
253 if (Tok
.K
== Identifier
&& Tok
.Value
[0] == '@') {
254 if (Tok
.Value
== "@") {
257 Tok
.Value
.getAsInteger(10, E
.Ordinal
);
258 } else if (Tok
.Value
.drop_front().getAsInteger(10, E
.Ordinal
)) {
259 // "foo \n @bar" - Not an ordinal modifier at all, but the next
260 // export (fastcall decorated) - complete the current one.
262 Info
.Exports
.push_back(E
);
263 return Error::success();
267 if (Tok
.K
== KwNoname
) {
274 if (Tok
.K
== KwData
) {
278 if (Tok
.K
== KwConstant
) {
282 if (Tok
.K
== KwPrivate
) {
286 if (Tok
.K
== EqualEqual
) {
288 E
.AliasTarget
= Tok
.Value
;
289 if (Machine
== IMAGE_FILE_MACHINE_I386
&& !isDecorated(E
.AliasTarget
, MingwDef
))
290 E
.AliasTarget
= std::string("_").append(E
.AliasTarget
);
294 Info
.Exports
.push_back(E
);
295 return Error::success();
299 // HEAPSIZE/STACKSIZE reserve[,commit]
300 Error
parseNumbers(uint64_t *Reserve
, uint64_t *Commit
) {
301 if (Error Err
= readAsInt(Reserve
))
304 if (Tok
.K
!= Comma
) {
307 return Error::success();
309 if (Error Err
= readAsInt(Commit
))
311 return Error::success();
314 // NAME outputPath [BASE=address]
315 Error
parseName(std::string
*Out
, uint64_t *Baseaddr
) {
317 if (Tok
.K
== Identifier
) {
322 return Error::success();
325 if (Tok
.K
== KwBase
) {
326 if (Error Err
= expect(Equal
, "'=' expected"))
328 if (Error Err
= readAsInt(Baseaddr
))
334 return Error::success();
337 // VERSION major[.minor]
338 Error
parseVersion(uint32_t *Major
, uint32_t *Minor
) {
340 if (Tok
.K
!= Identifier
)
341 return createError("identifier expected, but got " + Tok
.Value
);
343 std::tie(V1
, V2
) = Tok
.Value
.split('.');
344 if (V1
.getAsInteger(10, *Major
))
345 return createError("integer expected, but got " + Tok
.Value
);
348 else if (V2
.getAsInteger(10, *Minor
))
349 return createError("integer expected, but got " + Tok
.Value
);
350 return Error::success();
355 std::vector
<Token
> Stack
;
356 MachineTypes Machine
;
357 COFFModuleDefinition Info
;
361 Expected
<COFFModuleDefinition
> parseCOFFModuleDefinition(MemoryBufferRef MB
,
362 MachineTypes Machine
,
364 return Parser(MB
.getBuffer(), Machine
, MingwDef
).parse();
367 } // namespace object