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