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