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