xref: /freebsd/contrib/llvm-project/llvm/lib/MC/MCParser/COFFAsmParser.cpp (revision a3c35da61bb201168575f1d18f4ca3e96937d35c)
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 
73     // Win64 EH directives.
74     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
75                                                                    ".seh_proc");
76     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
77                                                                 ".seh_endproc");
78     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
79                                                            ".seh_startchained");
80     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
81                                                              ".seh_endchained");
82     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
83                                                                 ".seh_handler");
84     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
85                                                             ".seh_handlerdata");
86     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
87                                                                 ".seh_pushreg");
88     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
89                                                                ".seh_setframe");
90     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
91                                                              ".seh_stackalloc");
92     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
93                                                                 ".seh_savereg");
94     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
95                                                                 ".seh_savexmm");
96     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
97                                                               ".seh_pushframe");
98     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
99                                                             ".seh_endprologue");
100     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
101   }
102 
103   bool ParseSectionDirectiveText(StringRef, SMLoc) {
104     return ParseSectionSwitch(".text",
105                               COFF::IMAGE_SCN_CNT_CODE
106                             | COFF::IMAGE_SCN_MEM_EXECUTE
107                             | COFF::IMAGE_SCN_MEM_READ,
108                               SectionKind::getText());
109   }
110 
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                               SectionKind::getData());
116   }
117 
118   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
119     return ParseSectionSwitch(".bss",
120                               COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
121                             | COFF::IMAGE_SCN_MEM_READ
122                             | COFF::IMAGE_SCN_MEM_WRITE,
123                               SectionKind::getBSS());
124   }
125 
126   bool ParseDirectiveSection(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 
139   // Win64 EH directives.
140   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
141   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
142   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
143   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
144   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
145   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
146   bool ParseSEHDirectivePushReg(StringRef, SMLoc);
147   bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
148   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
149   bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
150   bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
151   bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
152   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
153 
154   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
155   bool ParseSEHRegisterNumber(unsigned &RegNo);
156   bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
157 
158 public:
159   COFFAsmParser() = default;
160 };
161 
162 } // end annonomous namespace.
163 
164 static SectionKind computeSectionKind(unsigned Flags) {
165   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
166     return SectionKind::getText();
167   if (Flags & COFF::IMAGE_SCN_MEM_READ &&
168       (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
169     return SectionKind::getReadOnly();
170   return SectionKind::getData();
171 }
172 
173 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
174                                       StringRef FlagsString, unsigned *Flags) {
175   enum {
176     None        = 0,
177     Alloc       = 1 << 0,
178     Code        = 1 << 1,
179     Load        = 1 << 2,
180     InitData    = 1 << 3,
181     Shared      = 1 << 4,
182     NoLoad      = 1 << 5,
183     NoRead      = 1 << 6,
184     NoWrite     = 1 << 7,
185     Discardable = 1 << 8,
186   };
187 
188   bool ReadOnlyRemoved = false;
189   unsigned SecFlags = None;
190 
191   for (char FlagChar : FlagsString) {
192     switch (FlagChar) {
193     case 'a':
194       // Ignored.
195       break;
196 
197     case 'b': // bss section
198       SecFlags |= Alloc;
199       if (SecFlags & InitData)
200         return TokError("conflicting section flags 'b' and 'd'.");
201       SecFlags &= ~Load;
202       break;
203 
204     case 'd': // data section
205       SecFlags |= InitData;
206       if (SecFlags & Alloc)
207         return TokError("conflicting section flags 'b' and 'd'.");
208       SecFlags &= ~NoWrite;
209       if ((SecFlags & NoLoad) == 0)
210         SecFlags |= Load;
211       break;
212 
213     case 'n': // section is not loaded
214       SecFlags |= NoLoad;
215       SecFlags &= ~Load;
216       break;
217 
218     case 'D': // discardable
219       SecFlags |= Discardable;
220       break;
221 
222     case 'r': // read-only
223       ReadOnlyRemoved = false;
224       SecFlags |= NoWrite;
225       if ((SecFlags & Code) == 0)
226         SecFlags |= InitData;
227       if ((SecFlags & NoLoad) == 0)
228         SecFlags |= Load;
229       break;
230 
231     case 's': // shared section
232       SecFlags |= Shared | InitData;
233       SecFlags &= ~NoWrite;
234       if ((SecFlags & NoLoad) == 0)
235         SecFlags |= Load;
236       break;
237 
238     case 'w': // writable
239       SecFlags &= ~NoWrite;
240       ReadOnlyRemoved = true;
241       break;
242 
243     case 'x': // executable section
244       SecFlags |= Code;
245       if ((SecFlags & NoLoad) == 0)
246         SecFlags |= Load;
247       if (!ReadOnlyRemoved)
248         SecFlags |= NoWrite;
249       break;
250 
251     case 'y': // not readable
252       SecFlags |= NoRead | NoWrite;
253       break;
254 
255     default:
256       return TokError("unknown flag");
257     }
258   }
259 
260   *Flags = 0;
261 
262   if (SecFlags == None)
263     SecFlags = InitData;
264 
265   if (SecFlags & Code)
266     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
267   if (SecFlags & InitData)
268     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
269   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
270     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
271   if (SecFlags & NoLoad)
272     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
273   if ((SecFlags & Discardable) ||
274       MCSectionCOFF::isImplicitlyDiscardable(SectionName))
275     *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
276   if ((SecFlags & NoRead) == 0)
277     *Flags |= COFF::IMAGE_SCN_MEM_READ;
278   if ((SecFlags & NoWrite) == 0)
279     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
280   if (SecFlags & Shared)
281     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
282 
283   return false;
284 }
285 
286 /// ParseDirectiveSymbolAttribute
287 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
288 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
289   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
290     .Case(".weak", MCSA_Weak)
291     .Default(MCSA_Invalid);
292   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
293   if (getLexer().isNot(AsmToken::EndOfStatement)) {
294     while (true) {
295       StringRef Name;
296 
297       if (getParser().parseIdentifier(Name))
298         return TokError("expected identifier in directive");
299 
300       MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
301 
302       getStreamer().EmitSymbolAttribute(Sym, Attr);
303 
304       if (getLexer().is(AsmToken::EndOfStatement))
305         break;
306 
307       if (getLexer().isNot(AsmToken::Comma))
308         return TokError("unexpected token in directive");
309       Lex();
310     }
311   }
312 
313   Lex();
314   return false;
315 }
316 
317 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
318                                        unsigned Characteristics,
319                                        SectionKind Kind) {
320   return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
321 }
322 
323 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
324                                        unsigned Characteristics,
325                                        SectionKind Kind,
326                                        StringRef COMDATSymName,
327                                        COFF::COMDATType Type) {
328   if (getLexer().isNot(AsmToken::EndOfStatement))
329     return TokError("unexpected token in section switching directive");
330   Lex();
331 
332   getStreamer().SwitchSection(getContext().getCOFFSection(
333       Section, Characteristics, Kind, COMDATSymName, Type));
334 
335   return false;
336 }
337 
338 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
339   if (!getLexer().is(AsmToken::Identifier))
340     return true;
341 
342   SectionName = getTok().getIdentifier();
343   Lex();
344   return false;
345 }
346 
347 // .section name [, "flags"] [, identifier [ identifier ], identifier]
348 //
349 // Supported flags:
350 //   a: Ignored.
351 //   b: BSS section (uninitialized data)
352 //   d: data section (initialized data)
353 //   n: "noload" section (removed by linker)
354 //   D: Discardable section
355 //   r: Readable section
356 //   s: Shared section
357 //   w: Writable section
358 //   x: Executable section
359 //   y: Not-readable section (clears 'r')
360 //
361 // Subsections are not supported.
362 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
363   StringRef SectionName;
364 
365   if (ParseSectionName(SectionName))
366     return TokError("expected identifier in directive");
367 
368   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
369                    COFF::IMAGE_SCN_MEM_READ |
370                    COFF::IMAGE_SCN_MEM_WRITE;
371 
372   if (getLexer().is(AsmToken::Comma)) {
373     Lex();
374 
375     if (getLexer().isNot(AsmToken::String))
376       return TokError("expected string in directive");
377 
378     StringRef FlagsStr = getTok().getStringContents();
379     Lex();
380 
381     if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
382       return true;
383   }
384 
385   COFF::COMDATType Type = (COFF::COMDATType)0;
386   StringRef COMDATSymName;
387   if (getLexer().is(AsmToken::Comma)) {
388     Type = COFF::IMAGE_COMDAT_SELECT_ANY;
389     Lex();
390 
391     Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
392 
393     if (!getLexer().is(AsmToken::Identifier))
394       return TokError("expected comdat type such as 'discard' or 'largest' "
395                       "after protection bits");
396 
397     if (parseCOMDATType(Type))
398       return true;
399 
400     if (getLexer().isNot(AsmToken::Comma))
401       return TokError("expected comma in directive");
402     Lex();
403 
404     if (getParser().parseIdentifier(COMDATSymName))
405       return TokError("expected identifier in directive");
406   }
407 
408   if (getLexer().isNot(AsmToken::EndOfStatement))
409     return TokError("unexpected token in directive");
410 
411   SectionKind Kind = computeSectionKind(Flags);
412   if (Kind.isText()) {
413     const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
414     if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
415       Flags |= COFF::IMAGE_SCN_MEM_16BIT;
416   }
417   ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
418   return false;
419 }
420 
421 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
422   StringRef SymbolName;
423 
424   if (getParser().parseIdentifier(SymbolName))
425     return TokError("expected identifier in directive");
426 
427   MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
428 
429   getStreamer().BeginCOFFSymbolDef(Sym);
430 
431   Lex();
432   return false;
433 }
434 
435 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
436   int64_t SymbolStorageClass;
437   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
438     return true;
439 
440   if (getLexer().isNot(AsmToken::EndOfStatement))
441     return TokError("unexpected token in directive");
442 
443   Lex();
444   getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
445   return false;
446 }
447 
448 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
449   int64_t Type;
450   if (getParser().parseAbsoluteExpression(Type))
451     return true;
452 
453   if (getLexer().isNot(AsmToken::EndOfStatement))
454     return TokError("unexpected token in directive");
455 
456   Lex();
457   getStreamer().EmitCOFFSymbolType(Type);
458   return false;
459 }
460 
461 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
462   Lex();
463   getStreamer().EndCOFFSymbolDef();
464   return false;
465 }
466 
467 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
468   StringRef SymbolID;
469   if (getParser().parseIdentifier(SymbolID))
470     return TokError("expected identifier in directive");
471 
472   int64_t Offset = 0;
473   SMLoc OffsetLoc;
474   if (getLexer().is(AsmToken::Plus)) {
475     OffsetLoc = getLexer().getLoc();
476     if (getParser().parseAbsoluteExpression(Offset))
477       return true;
478   }
479 
480   if (getLexer().isNot(AsmToken::EndOfStatement))
481     return TokError("unexpected token in directive");
482 
483   if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
484     return Error(
485         OffsetLoc,
486         "invalid '.secrel32' directive offset, can't be less "
487         "than zero or greater than std::numeric_limits<uint32_t>::max()");
488 
489   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
490 
491   Lex();
492   getStreamer().EmitCOFFSecRel32(Symbol, Offset);
493   return false;
494 }
495 
496 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
497   auto parseOp = [&]() -> bool {
498     StringRef SymbolID;
499     if (getParser().parseIdentifier(SymbolID))
500       return TokError("expected identifier in directive");
501 
502     int64_t Offset = 0;
503     SMLoc OffsetLoc;
504     if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
505       OffsetLoc = getLexer().getLoc();
506       if (getParser().parseAbsoluteExpression(Offset))
507         return true;
508     }
509 
510     if (Offset < std::numeric_limits<int32_t>::min() ||
511         Offset > std::numeric_limits<int32_t>::max())
512       return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
513                               "than -2147483648 or greater than "
514                               "2147483647");
515 
516     MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
517 
518     getStreamer().EmitCOFFImgRel32(Symbol, Offset);
519     return false;
520   };
521 
522   if (getParser().parseMany(parseOp))
523     return addErrorSuffix(" in directive");
524   return false;
525 }
526 
527 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
528   StringRef SymbolID;
529   if (getParser().parseIdentifier(SymbolID))
530     return TokError("expected identifier in directive");
531 
532   if (getLexer().isNot(AsmToken::EndOfStatement))
533     return TokError("unexpected token in directive");
534 
535   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
536 
537   Lex();
538   getStreamer().EmitCOFFSafeSEH(Symbol);
539   return false;
540 }
541 
542 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
543   StringRef SymbolID;
544   if (getParser().parseIdentifier(SymbolID))
545     return TokError("expected identifier in directive");
546 
547   if (getLexer().isNot(AsmToken::EndOfStatement))
548     return TokError("unexpected token in directive");
549 
550   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
551 
552   Lex();
553   getStreamer().EmitCOFFSectionIndex(Symbol);
554   return false;
555 }
556 
557 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
558   StringRef SymbolID;
559   if (getParser().parseIdentifier(SymbolID))
560     return TokError("expected identifier in directive");
561 
562   if (getLexer().isNot(AsmToken::EndOfStatement))
563     return TokError("unexpected token in directive");
564 
565   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
566 
567   Lex();
568   getStreamer().EmitCOFFSymbolIndex(Symbol);
569   return false;
570 }
571 
572 /// ::= [ identifier ]
573 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
574   StringRef TypeId = getTok().getIdentifier();
575 
576   Type = StringSwitch<COFF::COMDATType>(TypeId)
577     .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
578     .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
579     .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
580     .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
581     .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
582     .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
583     .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
584     .Default((COFF::COMDATType)0);
585 
586   if (Type == 0)
587     return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
588 
589   Lex();
590 
591   return false;
592 }
593 
594 /// ParseDirectiveLinkOnce
595 ///  ::= .linkonce [ identifier ]
596 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
597   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
598   if (getLexer().is(AsmToken::Identifier))
599     if (parseCOMDATType(Type))
600       return true;
601 
602   const MCSectionCOFF *Current =
603       static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
604 
605   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
606     return Error(Loc, "cannot make section associative with .linkonce");
607 
608   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
609     return Error(Loc, Twine("section '") + Current->getSectionName() +
610                                                        "' is already linkonce");
611 
612   Current->setSelection(Type);
613 
614   if (getLexer().isNot(AsmToken::EndOfStatement))
615     return TokError("unexpected token in directive");
616 
617   return false;
618 }
619 
620 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
621   StringRef SymbolID;
622   if (getParser().parseIdentifier(SymbolID))
623     return true;
624 
625   if (getLexer().isNot(AsmToken::EndOfStatement))
626     return TokError("unexpected token in directive");
627 
628   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
629 
630   Lex();
631   getStreamer().EmitWinCFIStartProc(Symbol, Loc);
632   return false;
633 }
634 
635 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
636   Lex();
637   getStreamer().EmitWinCFIEndProc(Loc);
638   return false;
639 }
640 
641 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
642   Lex();
643   getStreamer().EmitWinCFIStartChained(Loc);
644   return false;
645 }
646 
647 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
648   Lex();
649   getStreamer().EmitWinCFIEndChained(Loc);
650   return false;
651 }
652 
653 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
654   StringRef SymbolID;
655   if (getParser().parseIdentifier(SymbolID))
656     return true;
657 
658   if (getLexer().isNot(AsmToken::Comma))
659     return TokError("you must specify one or both of @unwind or @except");
660   Lex();
661   bool unwind = false, except = false;
662   if (ParseAtUnwindOrAtExcept(unwind, except))
663     return true;
664   if (getLexer().is(AsmToken::Comma)) {
665     Lex();
666     if (ParseAtUnwindOrAtExcept(unwind, except))
667       return true;
668   }
669   if (getLexer().isNot(AsmToken::EndOfStatement))
670     return TokError("unexpected token in directive");
671 
672   MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
673 
674   Lex();
675   getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
676   return false;
677 }
678 
679 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
680   Lex();
681   getStreamer().EmitWinEHHandlerData();
682   return false;
683 }
684 
685 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) {
686   unsigned Reg = 0;
687   if (ParseSEHRegisterNumber(Reg))
688     return true;
689 
690   if (getLexer().isNot(AsmToken::EndOfStatement))
691     return TokError("unexpected token in directive");
692 
693   Lex();
694   getStreamer().EmitWinCFIPushReg(Reg, Loc);
695   return false;
696 }
697 
698 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) {
699   unsigned Reg = 0;
700   int64_t Off;
701   if (ParseSEHRegisterNumber(Reg))
702     return true;
703   if (getLexer().isNot(AsmToken::Comma))
704     return TokError("you must specify a stack pointer offset");
705 
706   Lex();
707   if (getParser().parseAbsoluteExpression(Off))
708     return true;
709 
710   if (getLexer().isNot(AsmToken::EndOfStatement))
711     return TokError("unexpected token in directive");
712 
713   Lex();
714   getStreamer().EmitWinCFISetFrame(Reg, Off, Loc);
715   return false;
716 }
717 
718 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
719   int64_t Size;
720   if (getParser().parseAbsoluteExpression(Size))
721     return true;
722 
723   if (getLexer().isNot(AsmToken::EndOfStatement))
724     return TokError("unexpected token in directive");
725 
726   Lex();
727   getStreamer().EmitWinCFIAllocStack(Size, Loc);
728   return false;
729 }
730 
731 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) {
732   unsigned Reg = 0;
733   int64_t Off;
734   if (ParseSEHRegisterNumber(Reg))
735     return true;
736   if (getLexer().isNot(AsmToken::Comma))
737     return TokError("you must specify an offset on the stack");
738 
739   Lex();
740   if (getParser().parseAbsoluteExpression(Off))
741     return true;
742 
743   if (getLexer().isNot(AsmToken::EndOfStatement))
744     return TokError("unexpected token in directive");
745 
746   Lex();
747   // FIXME: Err on %xmm* registers
748   getStreamer().EmitWinCFISaveReg(Reg, Off, Loc);
749   return false;
750 }
751 
752 // FIXME: This method is inherently x86-specific. It should really be in the
753 // x86 backend.
754 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) {
755   unsigned Reg = 0;
756   int64_t Off;
757   if (ParseSEHRegisterNumber(Reg))
758     return true;
759   if (getLexer().isNot(AsmToken::Comma))
760     return TokError("you must specify an offset on the stack");
761 
762   Lex();
763   if (getParser().parseAbsoluteExpression(Off))
764     return true;
765 
766   if (getLexer().isNot(AsmToken::EndOfStatement))
767     return TokError("unexpected token in directive");
768 
769   Lex();
770   // FIXME: Err on non-%xmm* registers
771   getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc);
772   return false;
773 }
774 
775 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) {
776   bool Code = false;
777   StringRef CodeID;
778   if (getLexer().is(AsmToken::At)) {
779     SMLoc startLoc = getLexer().getLoc();
780     Lex();
781     if (!getParser().parseIdentifier(CodeID)) {
782       if (CodeID != "code")
783         return Error(startLoc, "expected @code");
784       Code = true;
785     }
786   }
787 
788   if (getLexer().isNot(AsmToken::EndOfStatement))
789     return TokError("unexpected token in directive");
790 
791   Lex();
792   getStreamer().EmitWinCFIPushFrame(Code, Loc);
793   return false;
794 }
795 
796 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
797   Lex();
798   getStreamer().EmitWinCFIEndProlog(Loc);
799   return false;
800 }
801 
802 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
803   StringRef identifier;
804   if (getLexer().isNot(AsmToken::At))
805     return TokError("a handler attribute must begin with '@'");
806   SMLoc startLoc = getLexer().getLoc();
807   Lex();
808   if (getParser().parseIdentifier(identifier))
809     return Error(startLoc, "expected @unwind or @except");
810   if (identifier == "unwind")
811     unwind = true;
812   else if (identifier == "except")
813     except = true;
814   else
815     return Error(startLoc, "expected @unwind or @except");
816   return false;
817 }
818 
819 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
820   SMLoc startLoc = getLexer().getLoc();
821   if (getLexer().is(AsmToken::Percent)) {
822     const MCRegisterInfo *MRI = getContext().getRegisterInfo();
823     SMLoc endLoc;
824     unsigned LLVMRegNo;
825     if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
826       return true;
827 
828 #if 0
829     // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
830     // violation so this validation code is disabled.
831 
832     // Check that this is a non-volatile register.
833     const unsigned *NVRegs = TAI.getCalleeSavedRegs();
834     unsigned i;
835     for (i = 0; NVRegs[i] != 0; ++i)
836       if (NVRegs[i] == LLVMRegNo)
837         break;
838     if (NVRegs[i] == 0)
839       return Error(startLoc, "expected non-volatile register");
840 #endif
841 
842     int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
843     if (SEHRegNo < 0)
844       return Error(startLoc,"register can't be represented in SEH unwind info");
845     RegNo = SEHRegNo;
846   }
847   else {
848     int64_t n;
849     if (getParser().parseAbsoluteExpression(n))
850       return true;
851     if (n > 15)
852       return Error(startLoc, "register number is too high");
853     RegNo = n;
854   }
855 
856   return false;
857 }
858 
859 namespace llvm {
860 
861 MCAsmParserExtension *createCOFFAsmParser() {
862   return new COFFAsmParser;
863 }
864 
865 } // end namespace llvm
866