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