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

source code of llvm/lib/MC/MCParser/COFFMasmParser.cpp