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