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