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