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