1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCRegisterInfo.h"
18 #include "llvm/MC/MCSectionCOFF.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCTargetAsmParser.h"
21 #include "llvm/Support/COFF.h"
22 using namespace llvm;
23 
24 namespace {
25 
26 class COFFAsmParser : public MCAsmParserExtension {
27   template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
28   void addDirectiveHandler(StringRef Directive) {
29     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30         this, HandleDirective<COFFAsmParser, HandlerMethod>);
31     getParser().addDirectiveHandler(Directive, Handler);
32   }
33 
34   bool ParseSectionSwitch(StringRef Section,
35                           unsigned Characteristics,
36                           SectionKind Kind);
37 
38   bool ParseSectionName(StringRef &SectionName);
39   bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
40 
41   virtual void Initialize(MCAsmParser &Parser) {
42     // Call the base implementation.
43     MCAsmParserExtension::Initialize(Parser);
44 
45     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
46     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
47     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
48     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
49     addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
50     addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
51     addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
52     addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
53     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
54     addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
55 
56     // Win64 EH directives.
57     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
58                                                                    ".seh_proc");
59     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
60                                                                 ".seh_endproc");
61     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
62                                                            ".seh_startchained");
63     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
64                                                              ".seh_endchained");
65     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
66                                                                 ".seh_handler");
67     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
68                                                             ".seh_handlerdata");
69     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
70                                                                 ".seh_pushreg");
71     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
72                                                                ".seh_setframe");
73     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
74                                                              ".seh_stackalloc");
75     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
76                                                                 ".seh_savereg");
77     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
78                                                                 ".seh_savexmm");
79     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
80                                                               ".seh_pushframe");
81     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
82                                                             ".seh_endprologue");
83     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
84   }
85 
86   bool ParseSectionDirectiveText(StringRef, SMLoc) {
87     return ParseSectionSwitch(".text",
88                               COFF::IMAGE_SCN_CNT_CODE
89                             | COFF::IMAGE_SCN_MEM_EXECUTE
90                             | COFF::IMAGE_SCN_MEM_READ,
91                               SectionKind::getText());
92   }
93   bool ParseSectionDirectiveData(StringRef, SMLoc) {
94     return ParseSectionSwitch(".data",
95                               COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
96                             | COFF::IMAGE_SCN_MEM_READ
97                             | COFF::IMAGE_SCN_MEM_WRITE,
98                               SectionKind::getDataRel());
99   }
100   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
101     return ParseSectionSwitch(".bss",
102                               COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
103                             | COFF::IMAGE_SCN_MEM_READ
104                             | COFF::IMAGE_SCN_MEM_WRITE,
105                               SectionKind::getBSS());
106   }
107 
108   bool ParseDirectiveSection(StringRef, SMLoc);
109   bool ParseDirectiveDef(StringRef, SMLoc);
110   bool ParseDirectiveScl(StringRef, SMLoc);
111   bool ParseDirectiveType(StringRef, SMLoc);
112   bool ParseDirectiveEndef(StringRef, SMLoc);
113   bool ParseDirectiveSecRel32(StringRef, SMLoc);
114   bool ParseDirectiveLinkOnce(StringRef, SMLoc);
115 
116   // Win64 EH directives.
117   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
118   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
119   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
120   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
121   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
122   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
123   bool ParseSEHDirectivePushReg(StringRef, SMLoc);
124   bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
125   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
126   bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
127   bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
128   bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
129   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
130 
131   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
132   bool ParseSEHRegisterNumber(unsigned &RegNo);
133   bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
134 public:
135   COFFAsmParser() {}
136 };
137 
138 } // end annonomous namespace.
139 
140 static SectionKind computeSectionKind(unsigned Flags) {
141   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
142     return SectionKind::getText();
143   if (Flags & COFF::IMAGE_SCN_MEM_READ &&
144       (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
145     return SectionKind::getReadOnly();
146   return SectionKind::getDataRel();
147 }
148 
149 bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
150   enum {
151     None      = 0,
152     Alloc     = 1 << 0,
153     Code      = 1 << 1,
154     Load      = 1 << 2,
155     InitData  = 1 << 3,
156     Shared    = 1 << 4,
157     NoLoad    = 1 << 5,
158     NoRead    = 1 << 6,
159     NoWrite  =  1 << 7
160   };
161 
162   bool ReadOnlyRemoved = false;
163   unsigned SecFlags = None;
164 
165   for (unsigned i = 0; i < FlagsString.size(); ++i) {
166     switch (FlagsString[i]) {
167     case 'a':
168       // Ignored.
169       break;
170 
171     case 'b': // bss section
172       SecFlags |= Alloc;
173       if (SecFlags & InitData)
174         return TokError("conflicting section flags 'b' and 'd'.");
175       SecFlags &= ~Load;
176       break;
177 
178     case 'd': // data section
179       SecFlags |= InitData;
180       if (SecFlags & Alloc)
181         return TokError("conflicting section flags 'b' and 'd'.");
182       SecFlags &= ~NoWrite;
183       if ((SecFlags & NoLoad) == 0)
184         SecFlags |= Load;
185       break;
186 
187     case 'n': // section is not loaded
188       SecFlags |= NoLoad;
189       SecFlags &= ~Load;
190       break;
191 
192     case 'r': // read-only
193       ReadOnlyRemoved = false;
194       SecFlags |= NoWrite;
195       if ((SecFlags & Code) == 0)
196         SecFlags |= InitData;
197       if ((SecFlags & NoLoad) == 0)
198         SecFlags |= Load;
199       break;
200 
201     case 's': // shared section
202       SecFlags |= Shared | InitData;
203       SecFlags &= ~NoWrite;
204       if ((SecFlags & NoLoad) == 0)
205         SecFlags |= Load;
206       break;
207 
208     case 'w': // writable
209       SecFlags &= ~NoWrite;
210       ReadOnlyRemoved = true;
211       break;
212 
213     case 'x': // executable section
214       SecFlags |= Code;
215       if ((SecFlags & NoLoad) == 0)
216         SecFlags |= Load;
217       if (!ReadOnlyRemoved)
218         SecFlags |= NoWrite;
219       break;
220 
221     case 'y': // not readable
222       SecFlags |= NoRead | NoWrite;
223       break;
224 
225     default:
226       return TokError("unknown flag");
227     }
228   }
229 
230   *Flags = 0;
231 
232   if (SecFlags == None)
233     SecFlags = InitData;
234 
235   if (SecFlags & Code)
236     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
237   if (SecFlags & InitData)
238     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
239   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
240     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
241   if (SecFlags & NoLoad)
242     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
243   if ((SecFlags & NoRead) == 0)
244     *Flags |= COFF::IMAGE_SCN_MEM_READ;
245   if ((SecFlags & NoWrite) == 0)
246     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
247   if (SecFlags & Shared)
248     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
249 
250   return false;
251 }
252 
253 /// ParseDirectiveSymbolAttribute
254 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
255 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
256   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
257     .Case(".weak", MCSA_Weak)
258     .Default(MCSA_Invalid);
259   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
260   if (getLexer().isNot(AsmToken::EndOfStatement)) {
261     for (;;) {
262       StringRef Name;
263 
264       if (getParser().parseIdentifier(Name))
265         return TokError("expected identifier in directive");
266 
267       MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
268 
269       getStreamer().EmitSymbolAttribute(Sym, Attr);
270 
271       if (getLexer().is(AsmToken::EndOfStatement))
272         break;
273 
274       if (getLexer().isNot(AsmToken::Comma))
275         return TokError("unexpected token in directive");
276       Lex();
277     }
278   }
279 
280   Lex();
281   return false;
282 }
283 
284 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
285                                        unsigned Characteristics,
286                                        SectionKind Kind) {
287   if (getLexer().isNot(AsmToken::EndOfStatement))
288     return TokError("unexpected token in section switching directive");
289   Lex();
290 
291   getStreamer().SwitchSection(getContext().getCOFFSection(
292                                 Section, Characteristics, Kind));
293 
294   return false;
295 }
296 
297 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
298   if (!getLexer().is(AsmToken::Identifier))
299     return true;
300 
301   SectionName = getTok().getIdentifier();
302   Lex();
303   return false;
304 }
305 
306 // .section name [, "flags"]
307 //
308 // Supported flags:
309 //   a: Ignored.
310 //   b: BSS section (uninitialized data)
311 //   d: data section (initialized data)
312 //   n: Discardable section
313 //   r: Readable section
314 //   s: Shared section
315 //   w: Writable section
316 //   x: Executable section
317 //   y: Not-readable section (clears 'r')
318 //
319 // Subsections are not supported.
320 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
321   StringRef SectionName;
322 
323   if (ParseSectionName(SectionName))
324     return TokError("expected identifier in directive");
325 
326   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
327                    COFF::IMAGE_SCN_MEM_READ |
328                    COFF::IMAGE_SCN_MEM_WRITE;
329 
330   if (getLexer().is(AsmToken::Comma)) {
331     Lex();
332 
333     if (getLexer().isNot(AsmToken::String))
334       return TokError("expected string in directive");
335 
336     StringRef FlagsStr = getTok().getStringContents();
337     Lex();
338 
339     if (ParseSectionFlags(FlagsStr, &Flags))
340       return true;
341   }
342 
343   if (getLexer().isNot(AsmToken::EndOfStatement))
344     return TokError("unexpected token in directive");
345 
346   SectionKind Kind = computeSectionKind(Flags);
347   ParseSectionSwitch(SectionName, Flags, Kind);
348   return false;
349 }
350 
351 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
352   StringRef SymbolName;
353 
354   if (getParser().parseIdentifier(SymbolName))
355     return TokError("expected identifier in directive");
356 
357   MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
358 
359   getStreamer().BeginCOFFSymbolDef(Sym);
360 
361   Lex();
362   return false;
363 }
364 
365 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
366   int64_t SymbolStorageClass;
367   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
368     return true;
369 
370   if (getLexer().isNot(AsmToken::EndOfStatement))
371     return TokError("unexpected token in directive");
372 
373   Lex();
374   getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
375   return false;
376 }
377 
378 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
379   int64_t Type;
380   if (getParser().parseAbsoluteExpression(Type))
381     return true;
382 
383   if (getLexer().isNot(AsmToken::EndOfStatement))
384     return TokError("unexpected token in directive");
385 
386   Lex();
387   getStreamer().EmitCOFFSymbolType(Type);
388   return false;
389 }
390 
391 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
392   Lex();
393   getStreamer().EndCOFFSymbolDef();
394   return false;
395 }
396 
397 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
398   StringRef SymbolID;
399   if (getParser().parseIdentifier(SymbolID))
400     return true;
401 
402   if (getLexer().isNot(AsmToken::EndOfStatement))
403     return TokError("unexpected token in directive");
404 
405   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
406 
407   Lex();
408   getStreamer().EmitCOFFSecRel32(Symbol);
409   return false;
410 }
411 
412 /// ParseDirectiveLinkOnce
413 ///  ::= .linkonce [ identifier [ identifier ] ]
414 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
415   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
416 
417   if (getLexer().is(AsmToken::Identifier)) {
418     StringRef TypeId = getTok().getIdentifier();
419 
420     Type = StringSwitch<COFF::COMDATType>(TypeId)
421       .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
422       .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
423       .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
424       .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
425       .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
426       .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
427       .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
428       .Default((COFF::COMDATType)0);
429 
430     if (Type == 0)
431       return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
432 
433     Lex();
434   }
435 
436   const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
437                                        getStreamer().getCurrentSection().first);
438 
439   const MCSectionCOFF *Assoc = 0;
440   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
441     StringRef AssocName;
442     SMLoc Loc = getTok().getLoc();
443     if (ParseSectionName(AssocName))
444       return TokError("expected associated section name");
445 
446     Assoc = static_cast<const MCSectionCOFF*>(
447                                         getContext().getCOFFSection(AssocName));
448     if (!Assoc)
449       return Error(Loc, "cannot associate unknown section '" + AssocName + "'");
450     if (Assoc == Current)
451       return Error(Loc, "cannot associate a section with itself");
452     if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT))
453       return Error(Loc, "associated section must be a COMDAT section");
454     if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
455       return Error(Loc, "associated section cannot be itself associative");
456   }
457 
458   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
459     return Error(Loc, Twine("section '") + Current->getSectionName() +
460                                                        "' is already linkonce");
461 
462   Current->setSelection(Type, Assoc);
463 
464   if (getLexer().isNot(AsmToken::EndOfStatement))
465     return TokError("unexpected token in directive");
466 
467   return false;
468 }
469 
470 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
471   StringRef SymbolID;
472   if (getParser().parseIdentifier(SymbolID))
473     return true;
474 
475   if (getLexer().isNot(AsmToken::EndOfStatement))
476     return TokError("unexpected token in directive");
477 
478   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
479 
480   Lex();
481   getStreamer().EmitWin64EHStartProc(Symbol);
482   return false;
483 }
484 
485 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
486   Lex();
487   getStreamer().EmitWin64EHEndProc();
488   return false;
489 }
490 
491 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
492   Lex();
493   getStreamer().EmitWin64EHStartChained();
494   return false;
495 }
496 
497 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
498   Lex();
499   getStreamer().EmitWin64EHEndChained();
500   return false;
501 }
502 
503 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
504   StringRef SymbolID;
505   if (getParser().parseIdentifier(SymbolID))
506     return true;
507 
508   if (getLexer().isNot(AsmToken::Comma))
509     return TokError("you must specify one or both of @unwind or @except");
510   Lex();
511   bool unwind = false, except = false;
512   if (ParseAtUnwindOrAtExcept(unwind, except))
513     return true;
514   if (getLexer().is(AsmToken::Comma)) {
515     Lex();
516     if (ParseAtUnwindOrAtExcept(unwind, except))
517       return true;
518   }
519   if (getLexer().isNot(AsmToken::EndOfStatement))
520     return TokError("unexpected token in directive");
521 
522   MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
523 
524   Lex();
525   getStreamer().EmitWin64EHHandler(handler, unwind, except);
526   return false;
527 }
528 
529 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
530   Lex();
531   getStreamer().EmitWin64EHHandlerData();
532   return false;
533 }
534 
535 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
536   unsigned Reg;
537   if (ParseSEHRegisterNumber(Reg))
538     return true;
539 
540   if (getLexer().isNot(AsmToken::EndOfStatement))
541     return TokError("unexpected token in directive");
542 
543   Lex();
544   getStreamer().EmitWin64EHPushReg(Reg);
545   return false;
546 }
547 
548 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
549   unsigned Reg;
550   int64_t Off;
551   if (ParseSEHRegisterNumber(Reg))
552     return true;
553   if (getLexer().isNot(AsmToken::Comma))
554     return TokError("you must specify a stack pointer offset");
555 
556   Lex();
557   SMLoc startLoc = getLexer().getLoc();
558   if (getParser().parseAbsoluteExpression(Off))
559     return true;
560 
561   if (Off & 0x0F)
562     return Error(startLoc, "offset is not a multiple of 16");
563 
564   if (getLexer().isNot(AsmToken::EndOfStatement))
565     return TokError("unexpected token in directive");
566 
567   Lex();
568   getStreamer().EmitWin64EHSetFrame(Reg, Off);
569   return false;
570 }
571 
572 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
573   int64_t Size;
574   SMLoc startLoc = getLexer().getLoc();
575   if (getParser().parseAbsoluteExpression(Size))
576     return true;
577 
578   if (Size & 7)
579     return Error(startLoc, "size is not a multiple of 8");
580 
581   if (getLexer().isNot(AsmToken::EndOfStatement))
582     return TokError("unexpected token in directive");
583 
584   Lex();
585   getStreamer().EmitWin64EHAllocStack(Size);
586   return false;
587 }
588 
589 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
590   unsigned Reg;
591   int64_t Off;
592   if (ParseSEHRegisterNumber(Reg))
593     return true;
594   if (getLexer().isNot(AsmToken::Comma))
595     return TokError("you must specify an offset on the stack");
596 
597   Lex();
598   SMLoc startLoc = getLexer().getLoc();
599   if (getParser().parseAbsoluteExpression(Off))
600     return true;
601 
602   if (Off & 7)
603     return Error(startLoc, "size is not a multiple of 8");
604 
605   if (getLexer().isNot(AsmToken::EndOfStatement))
606     return TokError("unexpected token in directive");
607 
608   Lex();
609   // FIXME: Err on %xmm* registers
610   getStreamer().EmitWin64EHSaveReg(Reg, Off);
611   return false;
612 }
613 
614 // FIXME: This method is inherently x86-specific. It should really be in the
615 // x86 backend.
616 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
617   unsigned Reg;
618   int64_t Off;
619   if (ParseSEHRegisterNumber(Reg))
620     return true;
621   if (getLexer().isNot(AsmToken::Comma))
622     return TokError("you must specify an offset on the stack");
623 
624   Lex();
625   SMLoc startLoc = getLexer().getLoc();
626   if (getParser().parseAbsoluteExpression(Off))
627     return true;
628 
629   if (getLexer().isNot(AsmToken::EndOfStatement))
630     return TokError("unexpected token in directive");
631 
632   if (Off & 0x0F)
633     return Error(startLoc, "offset is not a multiple of 16");
634 
635   Lex();
636   // FIXME: Err on non-%xmm* registers
637   getStreamer().EmitWin64EHSaveXMM(Reg, Off);
638   return false;
639 }
640 
641 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
642   bool Code = false;
643   StringRef CodeID;
644   if (getLexer().is(AsmToken::At)) {
645     SMLoc startLoc = getLexer().getLoc();
646     Lex();
647     if (!getParser().parseIdentifier(CodeID)) {
648       if (CodeID != "code")
649         return Error(startLoc, "expected @code");
650       Code = true;
651     }
652   }
653 
654   if (getLexer().isNot(AsmToken::EndOfStatement))
655     return TokError("unexpected token in directive");
656 
657   Lex();
658   getStreamer().EmitWin64EHPushFrame(Code);
659   return false;
660 }
661 
662 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
663   Lex();
664   getStreamer().EmitWin64EHEndProlog();
665   return false;
666 }
667 
668 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
669   StringRef identifier;
670   if (getLexer().isNot(AsmToken::At))
671     return TokError("a handler attribute must begin with '@'");
672   SMLoc startLoc = getLexer().getLoc();
673   Lex();
674   if (getParser().parseIdentifier(identifier))
675     return Error(startLoc, "expected @unwind or @except");
676   if (identifier == "unwind")
677     unwind = true;
678   else if (identifier == "except")
679     except = true;
680   else
681     return Error(startLoc, "expected @unwind or @except");
682   return false;
683 }
684 
685 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
686   SMLoc startLoc = getLexer().getLoc();
687   if (getLexer().is(AsmToken::Percent)) {
688     const MCRegisterInfo *MRI = getContext().getRegisterInfo();
689     SMLoc endLoc;
690     unsigned LLVMRegNo;
691     if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
692       return true;
693 
694 #if 0
695     // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
696     // violation so this validation code is disabled.
697 
698     // Check that this is a non-volatile register.
699     const unsigned *NVRegs = TAI.getCalleeSavedRegs();
700     unsigned i;
701     for (i = 0; NVRegs[i] != 0; ++i)
702       if (NVRegs[i] == LLVMRegNo)
703         break;
704     if (NVRegs[i] == 0)
705       return Error(startLoc, "expected non-volatile register");
706 #endif
707 
708     int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
709     if (SEHRegNo < 0)
710       return Error(startLoc,"register can't be represented in SEH unwind info");
711     RegNo = SEHRegNo;
712   }
713   else {
714     int64_t n;
715     if (getParser().parseAbsoluteExpression(n))
716       return true;
717     if (n > 15)
718       return Error(startLoc, "register number is too high");
719     RegNo = n;
720   }
721 
722   return false;
723 }
724 
725 namespace llvm {
726 
727 MCAsmParserExtension *createCOFFAsmParser() {
728   return new COFFAsmParser;
729 }
730 
731 }
732