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