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//===----------------------------------------------------------------------===//
59 // In def files, the symbols can either be listed decorated or undecorated.
61 // - For cdecl symbols, only the undecorated form is allowed.
62 // - For fastcall and vectorcall symbols, both fully decorated or
63 // undecorated forms can be present.
64 // - For stdcall symbols in non-MinGW environments, the decorated form is
65 // fully decorated with leading underscore and trailing stack argument
66 // size - like "_Func@0".
67 // - In MinGW def files, a decorated stdcall symbol does not include the
68 // leading underscore though, like "Func@0".
70 // This function controls whether a leading underscore should be added to
71 // the given symbol name or not. For MinGW, treat a stdcall symbol name such
72 // as "Func@0" as undecorated, i.e. a leading underscore must be added.
73 // For non-MinGW, look for '@' in the whole string and consider "_Func@0"
74 // as decorated, i.e. don't add any more leading underscores.
75 // We can't check for a leading underscore here, since function names
76 // themselves can start with an underscore, while a second one still needs
95 size_t End = Buf.find(
'\n');
96 Buf = (End == Buf.npos) ?
"" : Buf.drop_front(End);
100 Buf = Buf.drop_front();
101 if (Buf.consume_front(
"="))
105 Buf = Buf.drop_front();
113 size_t End = Buf.find_first_of(
"=,;\r\n \t\v");
129 Buf = (End == Buf.npos) ?
"" : Buf.drop_front(End);
130 return Token(K, Word);
142 : Lex(S), Machine(M), MingwDef(
B), AddUnderscores(AU) {
144 AddUnderscores =
false;
149 if (
Error Err = parseOne())
150 return std::move(Err);
151 }
while (Tok.K !=
Eof);
172 Error expect(
Kind Expected, StringRef Msg) {
174 if (Tok.K != Expected)
179 void unget() { Stack.push_back(Tok); }
193 if (
Error Err = parseExport())
197 return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
199 return parseNumbers(&Info.StackReserve, &Info.StackCommit);
202 bool IsDll = Tok.K ==
KwLibrary;
// Check before parseName.
204 if (
Error Err = parseName(&Name, &Info.ImageBase))
207 Info.ImportName =
Name;
209 // Set the output file, but don't override /out if it was already passed.
210 if (Info.OutputFile.empty()) {
211 Info.OutputFile =
Name;
212 // Append the appropriate file extension if not already present.
214 Info.OutputFile += IsDll ?
".dll" :
".exe";
220 return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
222 return createError(
"unknown directive: " + Tok.Value);
226 Error parseExport() {
228 E.Name = std::string(Tok.Value);
230 if (Tok.K ==
Equal) {
233 return createError(
"identifier expected, but got " + Tok.Value);
235 E.Name = std::string(Tok.Value);
240 if (AddUnderscores) {
241 // Don't add underscore if the name is already mangled or if it's a
244 (
E.ExtName.empty() || !StringRef(
E.Name).contains(
".")))
245 E.Name = (std::string(
"_").append(
E.Name));
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);
287 E.ImportName = std::string(Tok.Value);
290 // EXPORTAS must be at the end of export definition
295 "unexpected end of file, EXPORTAS identifier expected");
296 E.ExportAs = std::string(Tok.Value);
300 Info.Exports.push_back(
E);
305 // HEAPSIZE/STACKSIZE reserve[,commit]
306 Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
307 if (
Error Err = readAsInt(Reserve))
310 if (Tok.K !=
Comma) {
315 if (
Error Err = readAsInt(Commit))
320 // NAME outputPath [BASE=address]
321 Error parseName(std::string *Out, uint64_t *Baseaddr) {
324 *Out = std::string(Tok.Value);
332 if (
Error Err = expect(
Equal,
"'=' expected"))
334 if (
Error Err = readAsInt(Baseaddr))
343 // VERSION major[.minor]
344 Error parseVersion(uint32_t *Major, uint32_t *Minor) {
347 return createError(
"identifier expected, but got " + Tok.Value);
349 std::tie(V1, V2) = Tok.Value.split(
'.');
351 return createError(
"integer expected, but got " + Tok.Value);
355 return createError(
"integer expected, but got " + Tok.Value);
361 std::vector<Token> Stack;
363 COFFModuleDefinition Info;
371 bool AddUnderscores) {
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Function const char TargetMachine * Machine
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
StringRef getBuffer() const
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
empty - Check if the string is empty.
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Parser(StringRef S, MachineTypes M, bool B, bool AU)
Expected< COFFModuleDefinition > parse()
@ IMAGE_FILE_MACHINE_I386
Error createError(const Twine &Err)
LLVM_ABI Expected< COFFModuleDefinition > parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine, bool MingwDef=false, bool AddUnderscores=true)
static bool isDecorated(StringRef Sym, bool MingwDef)
LLVM_ABI bool has_extension(const Twine &path, Style style=Style::native)
Has extension?
This is an optimization pass for GlobalISel generic memory operations.
Token(Kind T=Unknown, StringRef S="")