xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCParser/COFFAsmParser.cpp (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
1 //===- COFFAsmParser.cpp - COFF 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/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/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
18 #include "llvm/MC/MCSectionCOFF.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/SectionKind.h"
21 #include "llvm/Support/SMLoc.h"
22 #include <cassert>
23 #include <cstdint>
24 #include <limits>
25 #include <utility>
26 
27 using namespace llvm;
28 
29 namespace {
30 
31 class COFFAsmParser : public MCAsmParserExtension {
32   template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
33   void addDirectiveHandler(StringRef Directive) {
34     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
35         this, HandleDirective<COFFAsmParser, HandlerMethod>);
36     getParser().addDirectiveHandler(Directive, Handler);
37   }
38 
39   bool ParseSectionSwitch(StringRef Section,
40                           unsigned Characteristics,
41                           SectionKind Kind);
42 
43   bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
44                           SectionKind Kind, StringRef COMDATSymName,
45                           COFF::COMDATType Type);
46 
47   bool ParseSectionName(StringRef &SectionName);
48   bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
49                          unsigned *Flags);
50 
51   void Initialize(MCAsmParser &Parser) override {
52     // Call the base implementation.
53     MCAsmParserExtension::Initialize(Parser);
54 
55     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
56     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
57     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
58     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
59     addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
60     addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
61     addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
62     addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
63     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
64     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
65     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
66     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
67     addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
68     addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
69     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
70     addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
71 
72     // Win64 EH directives.
73     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
74                                                                    ".seh_proc");
75     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
76                                                                 ".seh_endproc");
77     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc>(
78                                                                 ".seh_endfunclet");
79     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
80                                                            ".seh_startchained");
81     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
82                                                              ".seh_endchained");
83     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
84                                                                 ".seh_handler");
85     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
86                                                             ".seh_handlerdata");
87     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
88                                                              ".seh_stackalloc");
89     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
90                                                             ".seh_endprologue");
91   }
92 
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());
99   }
100 
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());
106   }
107 
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());
114   }
115 
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);
128   bool ParseDirectiveCGProfile(StringRef, SMLoc);
129 
130   // Win64 EH directives.
131   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
132   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
133   bool ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc);
134   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
135   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
136   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
137   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
138   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
139   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
140 
141   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
142   bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
143 
144 public:
145   COFFAsmParser() = default;
146 };
147 
148 } // end anonymous namespace.
149 
150 static SectionKind computeSectionKind(unsigned Flags) {
151   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
152     return SectionKind::getText();
153   if (Flags & COFF::IMAGE_SCN_MEM_READ &&
154       (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
155     return SectionKind::getReadOnly();
156   return SectionKind::getData();
157 }
158 
159 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
160                                       StringRef FlagsString, unsigned *Flags) {
161   enum {
162     None        = 0,
163     Alloc       = 1 << 0,
164     Code        = 1 << 1,
165     Load        = 1 << 2,
166     InitData    = 1 << 3,
167     Shared      = 1 << 4,
168     NoLoad      = 1 << 5,
169     NoRead      = 1 << 6,
170     NoWrite     = 1 << 7,
171     Discardable = 1 << 8,
172   };
173 
174   bool ReadOnlyRemoved = false;
175   unsigned SecFlags = None;
176 
177   for (char FlagChar : FlagsString) {
178     switch (FlagChar) {
179     case 'a':
180       // Ignored.
181       break;
182 
183     case 'b': // bss section
184       SecFlags |= Alloc;
185       if (SecFlags & InitData)
186         return TokError("conflicting section flags 'b' and 'd'.");
187       SecFlags &= ~Load;
188       break;
189 
190     case 'd': // data section
191       SecFlags |= InitData;
192       if (SecFlags & Alloc)
193         return TokError("conflicting section flags 'b' and 'd'.");
194       SecFlags &= ~NoWrite;
195       if ((SecFlags & NoLoad) == 0)
196         SecFlags |= Load;
197       break;
198 
199     case 'n': // section is not loaded
200       SecFlags |= NoLoad;
201       SecFlags &= ~Load;
202       break;
203 
204     case 'D': // discardable
205       SecFlags |= Discardable;
206       break;
207 
208     case 'r': // read-only
209       ReadOnlyRemoved = false;
210       SecFlags |= NoWrite;
211       if ((SecFlags & Code) == 0)
212         SecFlags |= InitData;
213       if ((SecFlags & NoLoad) == 0)
214         SecFlags |= Load;
215       break;
216 
217     case 's': // shared section
218       SecFlags |= Shared | InitData;
219       SecFlags &= ~NoWrite;
220       if ((SecFlags & NoLoad) == 0)
221         SecFlags |= Load;
222       break;
223 
224     case 'w': // writable
225       SecFlags &= ~NoWrite;
226       ReadOnlyRemoved = true;
227       break;
228 
229     case 'x': // executable section
230       SecFlags |= Code;
231       if ((SecFlags & NoLoad) == 0)
232         SecFlags |= Load;
233       if (!ReadOnlyRemoved)
234         SecFlags |= NoWrite;
235       break;
236 
237     case 'y': // not readable
238       SecFlags |= NoRead | NoWrite;
239       break;
240 
241     default:
242       return TokError("unknown flag");
243     }
244   }
245 
246   *Flags = 0;
247 
248   if (SecFlags == None)
249     SecFlags = InitData;
250 
251   if (SecFlags & Code)
252     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
253   if (SecFlags & InitData)
254     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
255   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
256     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
257   if (SecFlags & NoLoad)
258     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
259   if ((SecFlags & Discardable) ||
260       MCSectionCOFF::isImplicitlyDiscardable(SectionName))
261     *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
262   if ((SecFlags & NoRead) == 0)
263     *Flags |= COFF::IMAGE_SCN_MEM_READ;
264   if ((SecFlags & NoWrite) == 0)
265     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
266   if (SecFlags & Shared)
267     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
268 
269   return false;
270 }
271 
272 /// ParseDirectiveSymbolAttribute
273 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
274 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
275   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
276     .Case(".weak", MCSA_Weak)
277     .Default(MCSA_Invalid);
278   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
279   if (getLexer().isNot(AsmToken::EndOfStatement)) {
280     while (true) {
281       StringRef Name;
282 
283       if (getParser().parseIdentifier(Name))
284         return TokError("expected identifier in directive");
285 
286       MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
287 
288       getStreamer().emitSymbolAttribute(Sym, Attr);
289 
290       if (getLexer().is(AsmToken::EndOfStatement))
291         break;
292 
293       if (getLexer().isNot(AsmToken::Comma))
294         return TokError("unexpected token in directive");
295       Lex();
296     }
297   }
298 
299   Lex();
300   return false;
301 }
302 
303 bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) {
304   return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc);
305 }
306 
307 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
308                                        unsigned Characteristics,
309                                        SectionKind Kind) {
310   return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
311 }
312 
313 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
314                                        unsigned Characteristics,
315                                        SectionKind Kind,
316                                        StringRef COMDATSymName,
317                                        COFF::COMDATType Type) {
318   if (getLexer().isNot(AsmToken::EndOfStatement))
319     return TokError("unexpected token in section switching directive");
320   Lex();
321 
322   getStreamer().switchSection(getContext().getCOFFSection(
323       Section, Characteristics, Kind, COMDATSymName, Type));
324 
325   return false;
326 }
327 
328 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
329   if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String))
330     return true;
331 
332   SectionName = getTok().getIdentifier();
333   Lex();
334   return false;
335 }
336 
337 // .section name [, "flags"] [, identifier [ identifier ], identifier]
338 //
339 // Supported flags:
340 //   a: Ignored.
341 //   b: BSS section (uninitialized data)
342 //   d: data section (initialized data)
343 //   n: "noload" section (removed by linker)
344 //   D: Discardable section
345 //   r: Readable section
346 //   s: Shared section
347 //   w: Writable section
348 //   x: Executable section
349 //   y: Not-readable section (clears 'r')
350 //
351 // Subsections are not supported.
352 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
353   StringRef SectionName;
354 
355   if (ParseSectionName(SectionName))
356     return TokError("expected identifier in directive");
357 
358   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
359                    COFF::IMAGE_SCN_MEM_READ |
360                    COFF::IMAGE_SCN_MEM_WRITE;
361 
362   if (getLexer().is(AsmToken::Comma)) {
363     Lex();
364 
365     if (getLexer().isNot(AsmToken::String))
366       return TokError("expected string in directive");
367 
368     StringRef FlagsStr = getTok().getStringContents();
369     Lex();
370 
371     if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
372       return true;
373   }
374 
375   COFF::COMDATType Type = (COFF::COMDATType)0;
376   StringRef COMDATSymName;
377   if (getLexer().is(AsmToken::Comma)) {
378     Type = COFF::IMAGE_COMDAT_SELECT_ANY;
379     Lex();
380 
381     Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
382 
383     if (!getLexer().is(AsmToken::Identifier))
384       return TokError("expected comdat type such as 'discard' or 'largest' "
385                       "after protection bits");
386 
387     if (parseCOMDATType(Type))
388       return true;
389 
390     if (getLexer().isNot(AsmToken::Comma))
391       return TokError("expected comma in directive");
392     Lex();
393 
394     if (getParser().parseIdentifier(COMDATSymName))
395       return TokError("expected identifier in directive");
396   }
397 
398   if (getLexer().isNot(AsmToken::EndOfStatement))
399     return TokError("unexpected token in directive");
400 
401   SectionKind Kind = computeSectionKind(Flags);
402   if (Kind.isText()) {
403     const Triple &T = getContext().getTargetTriple();
404     if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
405       Flags |= COFF::IMAGE_SCN_MEM_16BIT;
406   }
407   ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
408   return false;
409 }
410 
411 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
412   StringRef SymbolName;
413 
414   if (getParser().parseIdentifier(SymbolName))
415     return TokError("expected identifier in directive");
416 
417   MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
418 
419   getStreamer().beginCOFFSymbolDef(Sym);
420 
421   Lex();
422   return false;
423 }
424 
425 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
426   int64_t SymbolStorageClass;
427   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
428     return true;
429 
430   if (getLexer().isNot(AsmToken::EndOfStatement))
431     return TokError("unexpected token in directive");
432 
433   Lex();
434   getStreamer().emitCOFFSymbolStorageClass(SymbolStorageClass);
435   return false;
436 }
437 
438 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
439   int64_t Type;
440   if (getParser().parseAbsoluteExpression(Type))
441     return true;
442 
443   if (getLexer().isNot(AsmToken::EndOfStatement))
444     return TokError("unexpected token in directive");
445 
446   Lex();
447   getStreamer().emitCOFFSymbolType(Type);
448   return false;
449 }
450 
451 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
452   Lex();
453   getStreamer().endCOFFSymbolDef();
454   return false;
455 }
456 
457 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
458   StringRef SymbolID;
459   if (getParser().parseIdentifier(SymbolID))
460     return TokError("expected identifier in directive");
461 
462   int64_t Offset = 0;
463   SMLoc OffsetLoc;
464   if (getLexer().is(AsmToken::Plus)) {
465     OffsetLoc = getLexer().getLoc();
466     if (getParser().parseAbsoluteExpression(Offset))
467       return true;
468   }
469 
470   if (getLexer().isNot(AsmToken::EndOfStatement))
471     return TokError("unexpected token in directive");
472 
473   if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
474     return Error(
475         OffsetLoc,
476         "invalid '.secrel32' directive offset, can't be less "
477         "than zero or greater than std::numeric_limits<uint32_t>::max()");
478 
479   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
480 
481   Lex();
482   getStreamer().emitCOFFSecRel32(Symbol, Offset);
483   return false;
484 }
485 
486 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
487   auto parseOp = [&]() -> bool {
488     StringRef SymbolID;
489     if (getParser().parseIdentifier(SymbolID))
490       return TokError("expected identifier in directive");
491 
492     int64_t Offset = 0;
493     SMLoc OffsetLoc;
494     if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
495       OffsetLoc = getLexer().getLoc();
496       if (getParser().parseAbsoluteExpression(Offset))
497         return true;
498     }
499 
500     if (Offset < std::numeric_limits<int32_t>::min() ||
501         Offset > std::numeric_limits<int32_t>::max())
502       return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
503                               "than -2147483648 or greater than "
504                               "2147483647");
505 
506     MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
507 
508     getStreamer().emitCOFFImgRel32(Symbol, Offset);
509     return false;
510   };
511 
512   if (getParser().parseMany(parseOp))
513     return addErrorSuffix(" in directive");
514   return false;
515 }
516 
517 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
518   StringRef SymbolID;
519   if (getParser().parseIdentifier(SymbolID))
520     return TokError("expected identifier in directive");
521 
522   if (getLexer().isNot(AsmToken::EndOfStatement))
523     return TokError("unexpected token in directive");
524 
525   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
526 
527   Lex();
528   getStreamer().emitCOFFSafeSEH(Symbol);
529   return false;
530 }
531 
532 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
533   StringRef SymbolID;
534   if (getParser().parseIdentifier(SymbolID))
535     return TokError("expected identifier in directive");
536 
537   if (getLexer().isNot(AsmToken::EndOfStatement))
538     return TokError("unexpected token in directive");
539 
540   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
541 
542   Lex();
543   getStreamer().emitCOFFSectionIndex(Symbol);
544   return false;
545 }
546 
547 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
548   StringRef SymbolID;
549   if (getParser().parseIdentifier(SymbolID))
550     return TokError("expected identifier in directive");
551 
552   if (getLexer().isNot(AsmToken::EndOfStatement))
553     return TokError("unexpected token in directive");
554 
555   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
556 
557   Lex();
558   getStreamer().emitCOFFSymbolIndex(Symbol);
559   return false;
560 }
561 
562 /// ::= [ identifier ]
563 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
564   StringRef TypeId = getTok().getIdentifier();
565 
566   Type = StringSwitch<COFF::COMDATType>(TypeId)
567     .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
568     .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
569     .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
570     .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
571     .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
572     .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
573     .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
574     .Default((COFF::COMDATType)0);
575 
576   if (Type == 0)
577     return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
578 
579   Lex();
580 
581   return false;
582 }
583 
584 /// ParseDirectiveLinkOnce
585 ///  ::= .linkonce [ identifier ]
586 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
587   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
588   if (getLexer().is(AsmToken::Identifier))
589     if (parseCOMDATType(Type))
590       return true;
591 
592   const MCSectionCOFF *Current =
593       static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
594 
595   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
596     return Error(Loc, "cannot make section associative with .linkonce");
597 
598   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
599     return Error(Loc, Twine("section '") + Current->getName() +
600                           "' is already linkonce");
601 
602   Current->setSelection(Type);
603 
604   if (getLexer().isNot(AsmToken::EndOfStatement))
605     return TokError("unexpected token in directive");
606 
607   return false;
608 }
609 
610 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
611   StringRef SymbolID;
612   if (getParser().parseIdentifier(SymbolID))
613     return true;
614 
615   if (getLexer().isNot(AsmToken::EndOfStatement))
616     return TokError("unexpected token in directive");
617 
618   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
619 
620   Lex();
621   getStreamer().emitWinCFIStartProc(Symbol, Loc);
622   return false;
623 }
624 
625 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
626   Lex();
627   getStreamer().emitWinCFIEndProc(Loc);
628   return false;
629 }
630 
631 bool COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) {
632   Lex();
633   getStreamer().emitWinCFIFuncletOrFuncEnd(Loc);
634   return false;
635 }
636 
637 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
638   Lex();
639   getStreamer().emitWinCFIStartChained(Loc);
640   return false;
641 }
642 
643 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
644   Lex();
645   getStreamer().emitWinCFIEndChained(Loc);
646   return false;
647 }
648 
649 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
650   StringRef SymbolID;
651   if (getParser().parseIdentifier(SymbolID))
652     return true;
653 
654   if (getLexer().isNot(AsmToken::Comma))
655     return TokError("you must specify one or both of @unwind or @except");
656   Lex();
657   bool unwind = false, except = false;
658   if (ParseAtUnwindOrAtExcept(unwind, except))
659     return true;
660   if (getLexer().is(AsmToken::Comma)) {
661     Lex();
662     if (ParseAtUnwindOrAtExcept(unwind, except))
663       return true;
664   }
665   if (getLexer().isNot(AsmToken::EndOfStatement))
666     return TokError("unexpected token in directive");
667 
668   MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
669 
670   Lex();
671   getStreamer().emitWinEHHandler(handler, unwind, except, Loc);
672   return false;
673 }
674 
675 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
676   Lex();
677   getStreamer().emitWinEHHandlerData();
678   return false;
679 }
680 
681 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
682   int64_t Size;
683   if (getParser().parseAbsoluteExpression(Size))
684     return true;
685 
686   if (getLexer().isNot(AsmToken::EndOfStatement))
687     return TokError("unexpected token in directive");
688 
689   Lex();
690   getStreamer().emitWinCFIAllocStack(Size, Loc);
691   return false;
692 }
693 
694 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
695   Lex();
696   getStreamer().emitWinCFIEndProlog(Loc);
697   return false;
698 }
699 
700 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
701   StringRef identifier;
702   if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))
703     return TokError("a handler attribute must begin with '@' or '%'");
704   SMLoc startLoc = getLexer().getLoc();
705   Lex();
706   if (getParser().parseIdentifier(identifier))
707     return Error(startLoc, "expected @unwind or @except");
708   if (identifier == "unwind")
709     unwind = true;
710   else if (identifier == "except")
711     except = true;
712   else
713     return Error(startLoc, "expected @unwind or @except");
714   return false;
715 }
716 
717 namespace llvm {
718 
719 MCAsmParserExtension *createCOFFAsmParser() {
720   return new COFFAsmParser;
721 }
722 
723 } // end namespace llvm
724