1//===- COFFMasmParser.cpp - COFF MASM Assembly Parser ---------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ADT/StringRef.h"
10#include "llvm/ADT/Twine.h"
11#include "llvm/BinaryFormat/COFF.h"
12#include "llvm/MC/MCAsmMacro.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCParser/AsmLexer.h"
15#include "llvm/MC/MCParser/MCAsmParserExtension.h"
16#include "llvm/MC/MCParser/MCTargetAsmParser.h"
17#include "llvm/MC/MCSectionCOFF.h"
18#include "llvm/MC/MCStreamer.h"
19#include "llvm/MC/MCSymbolCOFF.h"
20#include "llvm/MC/SectionKind.h"
21#include "llvm/Support/SMLoc.h"
22#include <cstdint>
23
24using namespace llvm;
25
26namespace {
27
28class COFFMasmParser : public MCAsmParserExtension {
29 template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
30 void addDirectiveHandler(StringRef Directive) {
31 MCAsmParser::ExtensionDirectiveHandler Handler =
32 std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
33 getParser().addDirectiveHandler(Directive, Handler);
34 }
35
36 bool parseSectionSwitch(StringRef SectionName, unsigned Characteristics);
37
38 bool parseSectionSwitch(StringRef SectionName, unsigned Characteristics,
39 StringRef COMDATSymName, COFF::COMDATType Type,
40 Align Alignment);
41
42 bool parseDirectiveProc(StringRef, SMLoc);
43 bool parseDirectiveEndProc(StringRef, SMLoc);
44 bool parseDirectiveSegment(StringRef, SMLoc);
45 bool parseDirectiveSegmentEnd(StringRef, SMLoc);
46 bool parseDirectiveIncludelib(StringRef, SMLoc);
47 bool parseDirectiveOption(StringRef, SMLoc);
48
49 bool parseDirectiveAlias(StringRef, SMLoc);
50
51 bool parseSEHDirectiveAllocStack(StringRef, SMLoc);
52 bool parseSEHDirectiveFreeStack(StringRef, SMLoc);
53 bool parseSEHDirectiveEndProlog(StringRef, SMLoc);
54 bool parseSEHDirectiveBeginEpilog(StringRef, SMLoc);
55 bool parseSEHDirectiveEndEpilog(StringRef, SMLoc);
56
57 /// Check that we are inside a PROC FRAME.
58 bool ensureInsideFrame(SMLoc Loc);
59 /// Check that we are in the prolog (before .endprolog).
60 bool ensureInProlog(SMLoc Loc);
61 /// Check that we are inside a .beginepilog/.endepilog block.
62 bool ensureInEpilog(SMLoc Loc);
63
64 bool IgnoreDirective(StringRef, SMLoc) {
65 while (!getLexer().is(K: AsmToken::EndOfStatement)) {
66 Lex();
67 }
68 return false;
69 }
70
71 void Initialize(MCAsmParser &Parser) override {
72 // Call the base implementation.
73 MCAsmParserExtension::Initialize(Parser);
74
75 // x64 directives
76 addDirectiveHandler<&COFFMasmParser::parseSEHDirectiveAllocStack>(
77 Directive: ".allocstack");
78 addDirectiveHandler<&COFFMasmParser::parseSEHDirectiveFreeStack>(
79 Directive: ".freestack");
80 addDirectiveHandler<&COFFMasmParser::parseSEHDirectiveEndProlog>(
81 Directive: ".endprolog");
82 addDirectiveHandler<&COFFMasmParser::parseSEHDirectiveBeginEpilog>(
83 Directive: ".beginepilog");
84 addDirectiveHandler<&COFFMasmParser::parseSEHDirectiveEndEpilog>(
85 Directive: ".endepilog");
86
87 // Code label directives
88 // label
89 // org
90
91 // Conditional control flow directives
92 // .break
93 // .continue
94 // .else
95 // .elseif
96 // .endif
97 // .endw
98 // .if
99 // .repeat
100 // .until
101 // .untilcxz
102 // .while
103
104 // Data allocation directives
105 // align
106 // even
107 // mmword
108 // tbyte
109 // xmmword
110 // ymmword
111
112 // Listing control directives
113 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".cref");
114 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".list");
115 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listall");
116 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listif");
117 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listmacro");
118 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listmacroall");
119 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nocref");
120 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolist");
121 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolistif");
122 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolistmacro");
123 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "page");
124 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "subtitle");
125 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".tfcond");
126 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "title");
127
128 // Macro directives
129 // goto
130
131 // Miscellaneous directives
132 addDirectiveHandler<&COFFMasmParser::parseDirectiveAlias>(Directive: "alias");
133 // assume
134 // .fpo
135 addDirectiveHandler<&COFFMasmParser::parseDirectiveIncludelib>(
136 Directive: "includelib");
137 addDirectiveHandler<&COFFMasmParser::parseDirectiveOption>(Directive: "option");
138 // popcontext
139 // pushcontext
140 // .safeseh
141
142 // Procedure directives
143 addDirectiveHandler<&COFFMasmParser::parseDirectiveEndProc>(Directive: "endp");
144 // invoke (32-bit only)
145 addDirectiveHandler<&COFFMasmParser::parseDirectiveProc>(Directive: "proc");
146 // proto
147
148 // Processor directives; all ignored
149 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".386");
150 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".386p");
151 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".387");
152 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".486");
153 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".486p");
154 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".586");
155 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".586p");
156 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".686");
157 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".686p");
158 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".k3d");
159 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".mmx");
160 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".xmm");
161
162 // Scope directives
163 // comm
164 // externdef
165
166 // Segment directives
167 // .alpha (32-bit only, order segments alphabetically)
168 // .dosseg (32-bit only, order segments in DOS convention)
169 // .seq (32-bit only, order segments sequentially)
170 addDirectiveHandler<&COFFMasmParser::parseDirectiveSegmentEnd>(Directive: "ends");
171 // group (32-bit only)
172 addDirectiveHandler<&COFFMasmParser::parseDirectiveSegment>(Directive: "segment");
173
174 // Simplified segment directives
175 addDirectiveHandler<&COFFMasmParser::parseSectionDirectiveCode>(Directive: ".code");
176 // .const
177 addDirectiveHandler<&COFFMasmParser::parseSectionDirectiveInitializedData>(
178 Directive: ".data");
179 addDirectiveHandler<
180 &COFFMasmParser::parseSectionDirectiveUninitializedData>(Directive: ".data?");
181 // .exit
182 // .fardata
183 // .fardata?
184 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".model");
185 // .stack
186 // .startup
187
188 // String directives, written <name> <directive> <params>
189 // catstr (equivalent to <name> TEXTEQU <params>)
190 // instr (equivalent to <name> = @InStr(<params>))
191 // sizestr (equivalent to <name> = @SizeStr(<params>))
192 // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
193
194 // Structure and record directives
195 // record
196 // typedef
197 }
198
199 bool parseSectionDirectiveCode(StringRef, SMLoc) {
200 return parseSectionSwitch(SectionName: ".text", Characteristics: COFF::IMAGE_SCN_CNT_CODE |
201 COFF::IMAGE_SCN_MEM_EXECUTE |
202 COFF::IMAGE_SCN_MEM_READ);
203 }
204
205 bool parseSectionDirectiveInitializedData(StringRef, SMLoc) {
206 return parseSectionSwitch(SectionName: ".data", Characteristics: COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
207 COFF::IMAGE_SCN_MEM_READ |
208 COFF::IMAGE_SCN_MEM_WRITE);
209 }
210
211 bool parseSectionDirectiveUninitializedData(StringRef, SMLoc) {
212 return parseSectionSwitch(SectionName: ".bss", Characteristics: COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
213 COFF::IMAGE_SCN_MEM_READ |
214 COFF::IMAGE_SCN_MEM_WRITE);
215 }
216
217 /// Stack of active procedure definitions.
218 SmallVector<StringRef, 1> CurrentProcedures;
219 SmallVector<bool, 1> CurrentProceduresFramed;
220
221public:
222 COFFMasmParser() = default;
223};
224
225} // end anonymous namespace.
226
227bool COFFMasmParser::parseSectionSwitch(StringRef SectionName,
228 unsigned Characteristics) {
229 return parseSectionSwitch(SectionName, Characteristics, COMDATSymName: "",
230 Type: (COFF::COMDATType)0, Alignment: Align(16));
231}
232
233bool COFFMasmParser::parseSectionSwitch(StringRef SectionName,
234 unsigned Characteristics,
235 StringRef COMDATSymName,
236 COFF::COMDATType Type,
237 Align Alignment) {
238 if (getLexer().isNot(K: AsmToken::EndOfStatement))
239 return TokError(Msg: "unexpected token in section switching directive");
240 Lex();
241
242 MCSection *Section = getContext().getCOFFSection(Section: SectionName, Characteristics,
243 COMDATSymName, Selection: Type);
244 Section->setAlignment(Alignment);
245 getStreamer().switchSection(Section);
246
247 return false;
248}
249
250bool COFFMasmParser::parseDirectiveSegment(StringRef Directive, SMLoc Loc) {
251 StringRef SegmentName;
252 if (!getLexer().is(K: AsmToken::Identifier))
253 return TokError(Msg: "expected identifier in directive");
254 SegmentName = getTok().getIdentifier();
255 Lex();
256
257 StringRef SectionName = SegmentName;
258 SmallVector<char, 247> SectionNameVector;
259
260 StringRef Class;
261 if (SegmentName == "_TEXT" || SegmentName.starts_with(Prefix: "_TEXT$")) {
262 if (SegmentName.size() == 5) {
263 SectionName = ".text";
264 } else {
265 SectionName =
266 (".text$" + SegmentName.substr(Start: 6)).toStringRef(Out&: SectionNameVector);
267 }
268 Class = "CODE";
269 }
270
271 // Parse all options to end of statement.
272 // Alignment defaults to PARA if unspecified.
273 int64_t Alignment = 16;
274 // Default flags are used only if no characteristics are set.
275 bool DefaultCharacteristics = true;
276 unsigned Flags = 0;
277 // "obsolete" according to the documentation, but still supported.
278 bool Readonly = false;
279 while (getLexer().isNot(K: AsmToken::EndOfStatement)) {
280 switch (getTok().getKind()) {
281 default:
282 break;
283 case AsmToken::String: {
284 // Class identifier; overrides Kind.
285 Class = getTok().getStringContents();
286 Lex();
287 break;
288 }
289 case AsmToken::Identifier: {
290 SMLoc KeywordLoc = getTok().getLoc();
291 StringRef Keyword;
292 if (getParser().parseIdentifier(Res&: Keyword)) {
293 llvm_unreachable("failed to parse identifier at an identifier token");
294 }
295 if (Keyword.equals_insensitive(RHS: "byte")) {
296 Alignment = 1;
297 } else if (Keyword.equals_insensitive(RHS: "word")) {
298 Alignment = 2;
299 } else if (Keyword.equals_insensitive(RHS: "dword")) {
300 Alignment = 4;
301 } else if (Keyword.equals_insensitive(RHS: "para")) {
302 Alignment = 16;
303 } else if (Keyword.equals_insensitive(RHS: "page")) {
304 Alignment = 256;
305 } else if (Keyword.equals_insensitive(RHS: "align")) {
306 if (getParser().parseToken(T: AsmToken::LParen) ||
307 getParser().parseIntToken(V&: Alignment,
308 ErrMsg: "Expected integer alignment") ||
309 getParser().parseToken(T: AsmToken::RParen)) {
310 return Error(L: getTok().getLoc(),
311 Msg: "Expected (n) following ALIGN in SEGMENT directive");
312 }
313 if (!isPowerOf2_64(Value: Alignment) || Alignment > 8192) {
314 return Error(L: KeywordLoc,
315 Msg: "ALIGN argument must be a power of 2 from 1 to 8192");
316 }
317 } else if (Keyword.equals_insensitive(RHS: "alias")) {
318 if (getParser().parseToken(T: AsmToken::LParen) ||
319 !getTok().is(K: AsmToken::String))
320 return Error(
321 L: getTok().getLoc(),
322 Msg: "Expected (string) following ALIAS in SEGMENT directive");
323 SectionName = getTok().getStringContents();
324 Lex();
325 if (getParser().parseToken(T: AsmToken::RParen))
326 return Error(
327 L: getTok().getLoc(),
328 Msg: "Expected (string) following ALIAS in SEGMENT directive");
329 } else if (Keyword.equals_insensitive(RHS: "readonly")) {
330 Readonly = true;
331 } else {
332 unsigned Characteristic =
333 StringSwitch<unsigned>(Keyword)
334 .CaseLower(S: "info", Value: COFF::IMAGE_SCN_LNK_INFO)
335 .CaseLower(S: "read", Value: COFF::IMAGE_SCN_MEM_READ)
336 .CaseLower(S: "write", Value: COFF::IMAGE_SCN_MEM_WRITE)
337 .CaseLower(S: "execute", Value: COFF::IMAGE_SCN_MEM_EXECUTE)
338 .CaseLower(S: "shared", Value: COFF::IMAGE_SCN_MEM_SHARED)
339 .CaseLower(S: "nopage", Value: COFF::IMAGE_SCN_MEM_NOT_PAGED)
340 .CaseLower(S: "nocache", Value: COFF::IMAGE_SCN_MEM_NOT_CACHED)
341 .CaseLower(S: "discard", Value: COFF::IMAGE_SCN_MEM_DISCARDABLE)
342 .Default(Value: -1);
343 if (Characteristic == static_cast<unsigned>(-1)) {
344 return Error(L: KeywordLoc,
345 Msg: "Expected characteristic in SEGMENT directive; found '" +
346 Keyword + "'");
347 }
348 Flags |= Characteristic;
349 DefaultCharacteristics = false;
350 }
351 }
352 }
353 }
354
355 SectionKind Kind = StringSwitch<SectionKind>(Class)
356 .CaseLower(S: "data", Value: SectionKind::getData())
357 .CaseLower(S: "code", Value: SectionKind::getText())
358 .CaseLower(S: "const", Value: SectionKind::getReadOnly())
359 .Default(Value: SectionKind::getData());
360 if (Kind.isText()) {
361 if (DefaultCharacteristics) {
362 Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ;
363 }
364 Flags |= COFF::IMAGE_SCN_CNT_CODE;
365 } else {
366 if (DefaultCharacteristics) {
367 Flags |= COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
368 }
369 Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
370 }
371 if (Readonly) {
372 Flags &= ~COFF::IMAGE_SCN_MEM_WRITE;
373 }
374
375 MCSection *Section = getContext().getCOFFSection(Section: SectionName, Characteristics: Flags, COMDATSymName: "",
376 Selection: (COFF::COMDATType)(0));
377 if (Alignment != 0) {
378 Section->setAlignment(Align(Alignment));
379 }
380 getStreamer().switchSection(Section);
381 return false;
382}
383
384/// parseDirectiveSegmentEnd
385/// ::= identifier "ends"
386bool COFFMasmParser::parseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
387 StringRef SegmentName;
388 if (!getLexer().is(K: AsmToken::Identifier))
389 return TokError(Msg: "expected identifier in directive");
390 SegmentName = getTok().getIdentifier();
391
392 // Ignore; no action necessary.
393 Lex();
394 return false;
395}
396
397/// parseDirectiveIncludelib
398/// ::= "includelib" identifier
399bool COFFMasmParser::parseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
400 StringRef Lib;
401 if (getParser().parseIdentifier(Res&: Lib))
402 return TokError(Msg: "expected identifier in includelib directive");
403
404 unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
405 getStreamer().pushSection();
406 getStreamer().switchSection(Section: getContext().getCOFFSection(
407 Section: ".drectve", Characteristics: Flags, COMDATSymName: "", Selection: (COFF::COMDATType)(0)));
408 getStreamer().emitBytes(Data: "/DEFAULTLIB:");
409 getStreamer().emitBytes(Data: Lib);
410 getStreamer().emitBytes(Data: " ");
411 getStreamer().popSection();
412 return false;
413}
414
415/// parseDirectiveOption
416/// ::= "option" option-list
417bool COFFMasmParser::parseDirectiveOption(StringRef Directive, SMLoc Loc) {
418 auto parseOption = [&]() -> bool {
419 StringRef Option;
420 if (getParser().parseIdentifier(Res&: Option))
421 return TokError(Msg: "expected identifier for option name");
422 if (Option.equals_insensitive(RHS: "prologue")) {
423 StringRef MacroId;
424 if (parseToken(T: AsmToken::Colon) || getParser().parseIdentifier(Res&: MacroId))
425 return TokError(Msg: "expected :macroId after OPTION PROLOGUE");
426 if (MacroId.equals_insensitive(RHS: "none")) {
427 // Since we currently don't implement prologues/epilogues, NONE is our
428 // default.
429 return false;
430 }
431 return TokError(Msg: "OPTION PROLOGUE is currently unsupported");
432 }
433 if (Option.equals_insensitive(RHS: "epilogue")) {
434 StringRef MacroId;
435 if (parseToken(T: AsmToken::Colon) || getParser().parseIdentifier(Res&: MacroId))
436 return TokError(Msg: "expected :macroId after OPTION EPILOGUE");
437 if (MacroId.equals_insensitive(RHS: "none")) {
438 // Since we currently don't implement prologues/epilogues, NONE is our
439 // default.
440 return false;
441 }
442 return TokError(Msg: "OPTION EPILOGUE is currently unsupported");
443 }
444 return TokError(Msg: "OPTION '" + Option + "' is currently unsupported");
445 };
446
447 if (parseMany(parseOne: parseOption))
448 return addErrorSuffix(Suffix: " in OPTION directive");
449 return false;
450}
451
452/// parseDirectiveProc
453/// TODO(epastor): Implement parameters and other attributes.
454/// ::= label "proc" [[distance]]
455/// statements
456/// label "endproc"
457bool COFFMasmParser::parseDirectiveProc(StringRef Directive, SMLoc Loc) {
458 if (!getStreamer().getCurrentFragment())
459 return Error(L: getTok().getLoc(), Msg: "expected section directive");
460
461 MCSymbol *Sym;
462 if (getParser().parseSymbol(Res&: Sym))
463 return Error(L: Loc, Msg: "expected identifier for procedure");
464 if (getLexer().is(K: AsmToken::Identifier)) {
465 StringRef nextVal = getTok().getString();
466 SMLoc nextLoc = getTok().getLoc();
467 if (nextVal.equals_insensitive(RHS: "far")) {
468 // TODO(epastor): Handle far procedure definitions.
469 Lex();
470 return Error(L: nextLoc, Msg: "far procedure definitions not yet supported");
471 } else if (nextVal.equals_insensitive(RHS: "near")) {
472 Lex();
473 nextVal = getTok().getString();
474 nextLoc = getTok().getLoc();
475 }
476 }
477
478 // Define symbol as simple external function
479 auto *COFFSym = static_cast<MCSymbolCOFF *>(Sym);
480 COFFSym->setExternal(true);
481 COFFSym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
482 << COFF::SCT_COMPLEX_TYPE_SHIFT);
483
484 bool Framed = false;
485 if (getLexer().is(K: AsmToken::Identifier) &&
486 getTok().getString().equals_insensitive(RHS: "frame")) {
487 Lex();
488 Framed = true;
489 getStreamer().emitWinCFIStartProc(Symbol: Sym, Loc);
490 }
491 getStreamer().emitLabel(Symbol: Sym, Loc);
492
493 CurrentProcedures.push_back(Elt: Sym->getName());
494 CurrentProceduresFramed.push_back(Elt: Framed);
495 return false;
496}
497bool COFFMasmParser::parseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
498 StringRef Label;
499 SMLoc LabelLoc = getTok().getLoc();
500 if (getParser().parseIdentifier(Res&: Label))
501 return Error(L: LabelLoc, Msg: "expected identifier for procedure end");
502
503 if (CurrentProcedures.empty())
504 return Error(L: Loc, Msg: "endp outside of procedure block");
505 else if (!CurrentProcedures.back().equals_insensitive(RHS: Label))
506 return Error(L: LabelLoc, Msg: "endp does not match current procedure '" +
507 CurrentProcedures.back() + "'");
508
509 if (CurrentProceduresFramed.back()) {
510 getStreamer().emitWinCFIEndProc(Loc);
511 }
512 CurrentProcedures.pop_back();
513 CurrentProceduresFramed.pop_back();
514 return false;
515}
516
517bool COFFMasmParser::parseDirectiveAlias(StringRef Directive, SMLoc Loc) {
518 std::string AliasName, ActualName;
519 if (getTok().isNot(K: AsmToken::Less) ||
520 getParser().parseAngleBracketString(Data&: AliasName))
521 return Error(L: getTok().getLoc(), Msg: "expected <aliasName>");
522 if (getParser().parseToken(T: AsmToken::Equal))
523 return addErrorSuffix(Suffix: " in " + Directive + " directive");
524 if (getTok().isNot(K: AsmToken::Less) ||
525 getParser().parseAngleBracketString(Data&: ActualName))
526 return Error(L: getTok().getLoc(), Msg: "expected <actualName>");
527
528 MCSymbol *Alias = getContext().parseSymbol(Name: AliasName);
529 MCSymbol *Actual = getContext().parseSymbol(Name: ActualName);
530
531 getStreamer().emitWeakReference(Alias, Symbol: Actual);
532
533 return false;
534}
535
536bool COFFMasmParser::ensureInsideFrame(SMLoc Loc) {
537 if (CurrentProceduresFramed.empty() || !CurrentProceduresFramed.back()) {
538 return Error(L: Loc,
539 Msg: "Missing Frame in proc, no unwind code will be generated.");
540 }
541 return false;
542}
543
544bool COFFMasmParser::ensureInProlog(SMLoc Loc) {
545 if (ensureInsideFrame(Loc))
546 return true;
547 if (getStreamer().isWinCFIPrologEnded()) {
548 return Error(L: Loc, Msg: "prolog directive must be used inside a prolog");
549 }
550 return false;
551}
552
553bool COFFMasmParser::ensureInEpilog(SMLoc Loc) {
554 if (ensureInsideFrame(Loc))
555 return true;
556 if (!getStreamer().isInEpilogCFI()) {
557 return Error(L: Loc, Msg: "epilog directive must be used inside an epilog");
558 }
559 return false;
560}
561
562bool COFFMasmParser::parseSEHDirectiveAllocStack(StringRef /*Directive*/,
563 SMLoc Loc) {
564 if (ensureInProlog(Loc))
565 return true;
566 int64_t Size;
567 SMLoc SizeLoc = getTok().getLoc();
568 if (getParser().parseAbsoluteExpression(Res&: Size))
569 return Error(L: SizeLoc, Msg: "expected integer size");
570 if (Size < 0)
571 return Error(L: SizeLoc, Msg: "stack size must be non-negative");
572 if (Size % 8 != 0)
573 return Error(L: SizeLoc, Msg: "stack size must be a multiple of 8");
574 getStreamer().emitWinCFIAllocStack(Size: static_cast<unsigned>(Size), Loc);
575 return false;
576}
577
578bool COFFMasmParser::parseSEHDirectiveFreeStack(StringRef /*Directive*/,
579 SMLoc Loc) {
580 if (ensureInEpilog(Loc))
581 return true;
582 int64_t Size;
583 SMLoc SizeLoc = getTok().getLoc();
584 if (getParser().parseAbsoluteExpression(Res&: Size))
585 return Error(L: SizeLoc, Msg: "expected integer size");
586 if (Size < 0)
587 return Error(L: SizeLoc, Msg: "stack size must be non-negative");
588 if (Size % 8 != 0)
589 return Error(L: SizeLoc, Msg: "stack size must be a multiple of 8");
590 getStreamer().emitWinCFIAllocStack(Size: static_cast<unsigned>(Size), Loc);
591 return false;
592}
593
594bool COFFMasmParser::parseSEHDirectiveEndProlog(StringRef /*Directive*/,
595 SMLoc Loc) {
596 if (ensureInsideFrame(Loc))
597 return true;
598 getStreamer().emitWinCFIEndProlog(Loc);
599 return false;
600}
601
602bool COFFMasmParser::parseSEHDirectiveBeginEpilog(StringRef /*Directive*/,
603 SMLoc Loc) {
604 if (ensureInsideFrame(Loc))
605 return true;
606 // .beginepilog is only valid after the prolog has ended (.endprolog) and
607 // when not already inside an epilog (i.e. after a prior .endepilog).
608 if (!getStreamer().isWinCFIPrologEnded() || getStreamer().isInEpilogCFI()) {
609 return Error(L: Loc, Msg: ".beginepilog must come after .endprolog or .endepilog");
610 }
611 getStreamer().emitWinCFIBeginEpilogue(Loc);
612 return false;
613}
614
615bool COFFMasmParser::parseSEHDirectiveEndEpilog(StringRef /*Directive*/,
616 SMLoc Loc) {
617 if (ensureInEpilog(Loc))
618 return true;
619 getStreamer().emitWinCFIEndEpilogue(Loc);
620 return false;
621}
622
623MCAsmParserExtension *llvm::createCOFFMasmParser() {
624 return new COFFMasmParser;
625}
626