1 //===- COFFAsmParser.cpp - COFF Assembly 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 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/StringSwitch.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCDirectives.h"
16 #include "llvm/MC/MCObjectFileInfo.h"
17 #include "llvm/MC/MCParser/MCAsmLexer.h"
18 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
19 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCSectionCOFF.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/SectionKind.h"
24 #include "llvm/Support/SMLoc.h"
34 class COFFAsmParser
: public MCAsmParserExtension
{
35 template<bool (COFFAsmParser::*HandlerMethod
)(StringRef
, SMLoc
)>
36 void addDirectiveHandler(StringRef Directive
) {
37 MCAsmParser::ExtensionDirectiveHandler Handler
= std::make_pair(
38 this, HandleDirective
<COFFAsmParser
, HandlerMethod
>);
39 getParser().addDirectiveHandler(Directive
, Handler
);
42 bool ParseSectionSwitch(StringRef Section
,
43 unsigned Characteristics
,
46 bool ParseSectionSwitch(StringRef Section
, unsigned Characteristics
,
47 SectionKind Kind
, StringRef COMDATSymName
,
48 COFF::COMDATType Type
);
50 bool ParseSectionName(StringRef
&SectionName
);
51 bool ParseSectionFlags(StringRef SectionName
, StringRef FlagsString
,
54 void Initialize(MCAsmParser
&Parser
) override
{
55 // Call the base implementation.
56 MCAsmParserExtension::Initialize(Parser
);
58 addDirectiveHandler
<&COFFAsmParser::ParseSectionDirectiveText
>(".text");
59 addDirectiveHandler
<&COFFAsmParser::ParseSectionDirectiveData
>(".data");
60 addDirectiveHandler
<&COFFAsmParser::ParseSectionDirectiveBSS
>(".bss");
61 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSection
>(".section");
62 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveDef
>(".def");
63 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveScl
>(".scl");
64 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveType
>(".type");
65 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveEndef
>(".endef");
66 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSecRel32
>(".secrel32");
67 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSymIdx
>(".symidx");
68 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSafeSEH
>(".safeseh");
69 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSecIdx
>(".secidx");
70 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveLinkOnce
>(".linkonce");
71 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveRVA
>(".rva");
72 addDirectiveHandler
<&COFFAsmParser::ParseDirectiveSymbolAttribute
>(".weak");
74 // Win64 EH directives.
75 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveStartProc
>(
77 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveEndProc
>(
79 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveStartChained
>(
81 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveEndChained
>(
83 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveHandler
>(
85 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveHandlerData
>(
87 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveAllocStack
>(
89 addDirectiveHandler
<&COFFAsmParser::ParseSEHDirectiveEndProlog
>(
93 bool ParseSectionDirectiveText(StringRef
, SMLoc
) {
94 return ParseSectionSwitch(".text",
95 COFF::IMAGE_SCN_CNT_CODE
96 | COFF::IMAGE_SCN_MEM_EXECUTE
97 | COFF::IMAGE_SCN_MEM_READ
,
98 SectionKind::getText());
101 bool ParseSectionDirectiveData(StringRef
, SMLoc
) {
102 return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
|
103 COFF::IMAGE_SCN_MEM_READ
|
104 COFF::IMAGE_SCN_MEM_WRITE
,
105 SectionKind::getData());
108 bool ParseSectionDirectiveBSS(StringRef
, SMLoc
) {
109 return ParseSectionSwitch(".bss",
110 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
111 | COFF::IMAGE_SCN_MEM_READ
112 | COFF::IMAGE_SCN_MEM_WRITE
,
113 SectionKind::getBSS());
116 bool ParseDirectiveSection(StringRef
, SMLoc
);
117 bool ParseDirectiveDef(StringRef
, SMLoc
);
118 bool ParseDirectiveScl(StringRef
, SMLoc
);
119 bool ParseDirectiveType(StringRef
, SMLoc
);
120 bool ParseDirectiveEndef(StringRef
, SMLoc
);
121 bool ParseDirectiveSecRel32(StringRef
, SMLoc
);
122 bool ParseDirectiveSecIdx(StringRef
, SMLoc
);
123 bool ParseDirectiveSafeSEH(StringRef
, SMLoc
);
124 bool ParseDirectiveSymIdx(StringRef
, SMLoc
);
125 bool parseCOMDATType(COFF::COMDATType
&Type
);
126 bool ParseDirectiveLinkOnce(StringRef
, SMLoc
);
127 bool ParseDirectiveRVA(StringRef
, SMLoc
);
129 // Win64 EH directives.
130 bool ParseSEHDirectiveStartProc(StringRef
, SMLoc
);
131 bool ParseSEHDirectiveEndProc(StringRef
, SMLoc
);
132 bool ParseSEHDirectiveStartChained(StringRef
, SMLoc
);
133 bool ParseSEHDirectiveEndChained(StringRef
, SMLoc
);
134 bool ParseSEHDirectiveHandler(StringRef
, SMLoc
);
135 bool ParseSEHDirectiveHandlerData(StringRef
, SMLoc
);
136 bool ParseSEHDirectiveAllocStack(StringRef
, SMLoc
);
137 bool ParseSEHDirectiveEndProlog(StringRef
, SMLoc
);
139 bool ParseAtUnwindOrAtExcept(bool &unwind
, bool &except
);
140 bool ParseSEHRegisterNumber(unsigned &RegNo
);
141 bool ParseDirectiveSymbolAttribute(StringRef Directive
, SMLoc
);
144 COFFAsmParser() = default;
147 } // end annonomous namespace.
149 static SectionKind
computeSectionKind(unsigned Flags
) {
150 if (Flags
& COFF::IMAGE_SCN_MEM_EXECUTE
)
151 return SectionKind::getText();
152 if (Flags
& COFF::IMAGE_SCN_MEM_READ
&&
153 (Flags
& COFF::IMAGE_SCN_MEM_WRITE
) == 0)
154 return SectionKind::getReadOnly();
155 return SectionKind::getData();
158 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName
,
159 StringRef FlagsString
, unsigned *Flags
) {
170 Discardable
= 1 << 8,
173 bool ReadOnlyRemoved
= false;
174 unsigned SecFlags
= None
;
176 for (char FlagChar
: FlagsString
) {
182 case 'b': // bss section
184 if (SecFlags
& InitData
)
185 return TokError("conflicting section flags 'b' and 'd'.");
189 case 'd': // data section
190 SecFlags
|= InitData
;
191 if (SecFlags
& Alloc
)
192 return TokError("conflicting section flags 'b' and 'd'.");
193 SecFlags
&= ~NoWrite
;
194 if ((SecFlags
& NoLoad
) == 0)
198 case 'n': // section is not loaded
203 case 'D': // discardable
204 SecFlags
|= Discardable
;
207 case 'r': // read-only
208 ReadOnlyRemoved
= false;
210 if ((SecFlags
& Code
) == 0)
211 SecFlags
|= InitData
;
212 if ((SecFlags
& NoLoad
) == 0)
216 case 's': // shared section
217 SecFlags
|= Shared
| InitData
;
218 SecFlags
&= ~NoWrite
;
219 if ((SecFlags
& NoLoad
) == 0)
223 case 'w': // writable
224 SecFlags
&= ~NoWrite
;
225 ReadOnlyRemoved
= true;
228 case 'x': // executable section
230 if ((SecFlags
& NoLoad
) == 0)
232 if (!ReadOnlyRemoved
)
236 case 'y': // not readable
237 SecFlags
|= NoRead
| NoWrite
;
241 return TokError("unknown flag");
247 if (SecFlags
== None
)
251 *Flags
|= COFF::IMAGE_SCN_CNT_CODE
| COFF::IMAGE_SCN_MEM_EXECUTE
;
252 if (SecFlags
& InitData
)
253 *Flags
|= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
;
254 if ((SecFlags
& Alloc
) && (SecFlags
& Load
) == 0)
255 *Flags
|= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
;
256 if (SecFlags
& NoLoad
)
257 *Flags
|= COFF::IMAGE_SCN_LNK_REMOVE
;
258 if ((SecFlags
& Discardable
) ||
259 MCSectionCOFF::isImplicitlyDiscardable(SectionName
))
260 *Flags
|= COFF::IMAGE_SCN_MEM_DISCARDABLE
;
261 if ((SecFlags
& NoRead
) == 0)
262 *Flags
|= COFF::IMAGE_SCN_MEM_READ
;
263 if ((SecFlags
& NoWrite
) == 0)
264 *Flags
|= COFF::IMAGE_SCN_MEM_WRITE
;
265 if (SecFlags
& Shared
)
266 *Flags
|= COFF::IMAGE_SCN_MEM_SHARED
;
271 /// ParseDirectiveSymbolAttribute
272 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
273 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive
, SMLoc
) {
274 MCSymbolAttr Attr
= StringSwitch
<MCSymbolAttr
>(Directive
)
275 .Case(".weak", MCSA_Weak
)
276 .Default(MCSA_Invalid
);
277 assert(Attr
!= MCSA_Invalid
&& "unexpected symbol attribute directive!");
278 if (getLexer().isNot(AsmToken::EndOfStatement
)) {
282 if (getParser().parseIdentifier(Name
))
283 return TokError("expected identifier in directive");
285 MCSymbol
*Sym
= getContext().getOrCreateSymbol(Name
);
287 getStreamer().EmitSymbolAttribute(Sym
, Attr
);
289 if (getLexer().is(AsmToken::EndOfStatement
))
292 if (getLexer().isNot(AsmToken::Comma
))
293 return TokError("unexpected token in directive");
302 bool COFFAsmParser::ParseSectionSwitch(StringRef Section
,
303 unsigned Characteristics
,
305 return ParseSectionSwitch(Section
, Characteristics
, Kind
, "", (COFF::COMDATType
)0);
308 bool COFFAsmParser::ParseSectionSwitch(StringRef Section
,
309 unsigned Characteristics
,
311 StringRef COMDATSymName
,
312 COFF::COMDATType Type
) {
313 if (getLexer().isNot(AsmToken::EndOfStatement
))
314 return TokError("unexpected token in section switching directive");
317 getStreamer().SwitchSection(getContext().getCOFFSection(
318 Section
, Characteristics
, Kind
, COMDATSymName
, Type
));
323 bool COFFAsmParser::ParseSectionName(StringRef
&SectionName
) {
324 if (!getLexer().is(AsmToken::Identifier
))
327 SectionName
= getTok().getIdentifier();
332 // .section name [, "flags"] [, identifier [ identifier ], identifier]
336 // b: BSS section (uninitialized data)
337 // d: data section (initialized data)
338 // n: "noload" section (removed by linker)
339 // D: Discardable section
340 // r: Readable section
342 // w: Writable section
343 // x: Executable section
344 // y: Not-readable section (clears 'r')
346 // Subsections are not supported.
347 bool COFFAsmParser::ParseDirectiveSection(StringRef
, SMLoc
) {
348 StringRef SectionName
;
350 if (ParseSectionName(SectionName
))
351 return TokError("expected identifier in directive");
353 unsigned Flags
= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
|
354 COFF::IMAGE_SCN_MEM_READ
|
355 COFF::IMAGE_SCN_MEM_WRITE
;
357 if (getLexer().is(AsmToken::Comma
)) {
360 if (getLexer().isNot(AsmToken::String
))
361 return TokError("expected string in directive");
363 StringRef FlagsStr
= getTok().getStringContents();
366 if (ParseSectionFlags(SectionName
, FlagsStr
, &Flags
))
370 COFF::COMDATType Type
= (COFF::COMDATType
)0;
371 StringRef COMDATSymName
;
372 if (getLexer().is(AsmToken::Comma
)) {
373 Type
= COFF::IMAGE_COMDAT_SELECT_ANY
;
376 Flags
|= COFF::IMAGE_SCN_LNK_COMDAT
;
378 if (!getLexer().is(AsmToken::Identifier
))
379 return TokError("expected comdat type such as 'discard' or 'largest' "
380 "after protection bits");
382 if (parseCOMDATType(Type
))
385 if (getLexer().isNot(AsmToken::Comma
))
386 return TokError("expected comma in directive");
389 if (getParser().parseIdentifier(COMDATSymName
))
390 return TokError("expected identifier in directive");
393 if (getLexer().isNot(AsmToken::EndOfStatement
))
394 return TokError("unexpected token in directive");
396 SectionKind Kind
= computeSectionKind(Flags
);
398 const Triple
&T
= getContext().getObjectFileInfo()->getTargetTriple();
399 if (T
.getArch() == Triple::arm
|| T
.getArch() == Triple::thumb
)
400 Flags
|= COFF::IMAGE_SCN_MEM_16BIT
;
402 ParseSectionSwitch(SectionName
, Flags
, Kind
, COMDATSymName
, Type
);
406 bool COFFAsmParser::ParseDirectiveDef(StringRef
, SMLoc
) {
407 StringRef SymbolName
;
409 if (getParser().parseIdentifier(SymbolName
))
410 return TokError("expected identifier in directive");
412 MCSymbol
*Sym
= getContext().getOrCreateSymbol(SymbolName
);
414 getStreamer().BeginCOFFSymbolDef(Sym
);
420 bool COFFAsmParser::ParseDirectiveScl(StringRef
, SMLoc
) {
421 int64_t SymbolStorageClass
;
422 if (getParser().parseAbsoluteExpression(SymbolStorageClass
))
425 if (getLexer().isNot(AsmToken::EndOfStatement
))
426 return TokError("unexpected token in directive");
429 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass
);
433 bool COFFAsmParser::ParseDirectiveType(StringRef
, SMLoc
) {
435 if (getParser().parseAbsoluteExpression(Type
))
438 if (getLexer().isNot(AsmToken::EndOfStatement
))
439 return TokError("unexpected token in directive");
442 getStreamer().EmitCOFFSymbolType(Type
);
446 bool COFFAsmParser::ParseDirectiveEndef(StringRef
, SMLoc
) {
448 getStreamer().EndCOFFSymbolDef();
452 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef
, SMLoc
) {
454 if (getParser().parseIdentifier(SymbolID
))
455 return TokError("expected identifier in directive");
459 if (getLexer().is(AsmToken::Plus
)) {
460 OffsetLoc
= getLexer().getLoc();
461 if (getParser().parseAbsoluteExpression(Offset
))
465 if (getLexer().isNot(AsmToken::EndOfStatement
))
466 return TokError("unexpected token in directive");
468 if (Offset
< 0 || Offset
> std::numeric_limits
<uint32_t>::max())
471 "invalid '.secrel32' directive offset, can't be less "
472 "than zero or greater than std::numeric_limits<uint32_t>::max()");
474 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
477 getStreamer().EmitCOFFSecRel32(Symbol
, Offset
);
481 bool COFFAsmParser::ParseDirectiveRVA(StringRef
, SMLoc
) {
482 auto parseOp
= [&]() -> bool {
484 if (getParser().parseIdentifier(SymbolID
))
485 return TokError("expected identifier in directive");
489 if (getLexer().is(AsmToken::Plus
) || getLexer().is(AsmToken::Minus
)) {
490 OffsetLoc
= getLexer().getLoc();
491 if (getParser().parseAbsoluteExpression(Offset
))
495 if (Offset
< std::numeric_limits
<int32_t>::min() ||
496 Offset
> std::numeric_limits
<int32_t>::max())
497 return Error(OffsetLoc
, "invalid '.rva' directive offset, can't be less "
498 "than -2147483648 or greater than "
501 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
503 getStreamer().EmitCOFFImgRel32(Symbol
, Offset
);
507 if (getParser().parseMany(parseOp
))
508 return addErrorSuffix(" in directive");
512 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef
, SMLoc
) {
514 if (getParser().parseIdentifier(SymbolID
))
515 return TokError("expected identifier in directive");
517 if (getLexer().isNot(AsmToken::EndOfStatement
))
518 return TokError("unexpected token in directive");
520 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
523 getStreamer().EmitCOFFSafeSEH(Symbol
);
527 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef
, SMLoc
) {
529 if (getParser().parseIdentifier(SymbolID
))
530 return TokError("expected identifier in directive");
532 if (getLexer().isNot(AsmToken::EndOfStatement
))
533 return TokError("unexpected token in directive");
535 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
538 getStreamer().EmitCOFFSectionIndex(Symbol
);
542 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef
, SMLoc
) {
544 if (getParser().parseIdentifier(SymbolID
))
545 return TokError("expected identifier in directive");
547 if (getLexer().isNot(AsmToken::EndOfStatement
))
548 return TokError("unexpected token in directive");
550 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
553 getStreamer().EmitCOFFSymbolIndex(Symbol
);
557 /// ::= [ identifier ]
558 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType
&Type
) {
559 StringRef TypeId
= getTok().getIdentifier();
561 Type
= StringSwitch
<COFF::COMDATType
>(TypeId
)
562 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES
)
563 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY
)
564 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE
)
565 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH
)
566 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
)
567 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST
)
568 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST
)
569 .Default((COFF::COMDATType
)0);
572 return TokError(Twine("unrecognized COMDAT type '" + TypeId
+ "'"));
579 /// ParseDirectiveLinkOnce
580 /// ::= .linkonce [ identifier ]
581 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef
, SMLoc Loc
) {
582 COFF::COMDATType Type
= COFF::IMAGE_COMDAT_SELECT_ANY
;
583 if (getLexer().is(AsmToken::Identifier
))
584 if (parseCOMDATType(Type
))
587 const MCSectionCOFF
*Current
=
588 static_cast<const MCSectionCOFF
*>(getStreamer().getCurrentSectionOnly());
590 if (Type
== COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE
)
591 return Error(Loc
, "cannot make section associative with .linkonce");
593 if (Current
->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT
)
594 return Error(Loc
, Twine("section '") + Current
->getSectionName() +
595 "' is already linkonce");
597 Current
->setSelection(Type
);
599 if (getLexer().isNot(AsmToken::EndOfStatement
))
600 return TokError("unexpected token in directive");
605 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef
, SMLoc Loc
) {
607 if (getParser().parseIdentifier(SymbolID
))
610 if (getLexer().isNot(AsmToken::EndOfStatement
))
611 return TokError("unexpected token in directive");
613 MCSymbol
*Symbol
= getContext().getOrCreateSymbol(SymbolID
);
616 getStreamer().EmitWinCFIStartProc(Symbol
, Loc
);
620 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef
, SMLoc Loc
) {
622 getStreamer().EmitWinCFIEndProc(Loc
);
626 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef
, SMLoc Loc
) {
628 getStreamer().EmitWinCFIStartChained(Loc
);
632 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef
, SMLoc Loc
) {
634 getStreamer().EmitWinCFIEndChained(Loc
);
638 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef
, SMLoc Loc
) {
640 if (getParser().parseIdentifier(SymbolID
))
643 if (getLexer().isNot(AsmToken::Comma
))
644 return TokError("you must specify one or both of @unwind or @except");
646 bool unwind
= false, except
= false;
647 if (ParseAtUnwindOrAtExcept(unwind
, except
))
649 if (getLexer().is(AsmToken::Comma
)) {
651 if (ParseAtUnwindOrAtExcept(unwind
, except
))
654 if (getLexer().isNot(AsmToken::EndOfStatement
))
655 return TokError("unexpected token in directive");
657 MCSymbol
*handler
= getContext().getOrCreateSymbol(SymbolID
);
660 getStreamer().EmitWinEHHandler(handler
, unwind
, except
, Loc
);
664 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef
, SMLoc Loc
) {
666 getStreamer().EmitWinEHHandlerData();
670 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef
, SMLoc Loc
) {
672 if (getParser().parseAbsoluteExpression(Size
))
675 if (getLexer().isNot(AsmToken::EndOfStatement
))
676 return TokError("unexpected token in directive");
679 getStreamer().EmitWinCFIAllocStack(Size
, Loc
);
683 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef
, SMLoc Loc
) {
685 getStreamer().EmitWinCFIEndProlog(Loc
);
689 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind
, bool &except
) {
690 StringRef identifier
;
691 if (getLexer().isNot(AsmToken::At
))
692 return TokError("a handler attribute must begin with '@'");
693 SMLoc startLoc
= getLexer().getLoc();
695 if (getParser().parseIdentifier(identifier
))
696 return Error(startLoc
, "expected @unwind or @except");
697 if (identifier
== "unwind")
699 else if (identifier
== "except")
702 return Error(startLoc
, "expected @unwind or @except");
708 MCAsmParserExtension
*createCOFFAsmParser() {
709 return new COFFAsmParser
;
712 } // end namespace llvm