COFFAsmParser.cpp revision dce4a407a24b04eebc6a376f8e62b41aaa7b071f
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"
22using namespace llvm;
23
24namespace {
25
26class 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 ParseSectionSwitch(StringRef Section, unsigned Characteristics,
39                          SectionKind Kind, StringRef COMDATSymName,
40                          COFF::COMDATType Type, const MCSectionCOFF *Assoc);
41
42  bool ParseSectionName(StringRef &SectionName);
43  bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
44
45  void Initialize(MCAsmParser &Parser) override {
46    // Call the base implementation.
47    MCAsmParserExtension::Initialize(Parser);
48
49    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
50    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
51    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
52    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
53    addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
54    addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
55    addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
56    addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
57    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
58    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
59    addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
60
61    // Win64 EH directives.
62    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
63                                                                   ".seh_proc");
64    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
65                                                                ".seh_endproc");
66    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
67                                                           ".seh_startchained");
68    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
69                                                             ".seh_endchained");
70    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
71                                                                ".seh_handler");
72    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
73                                                            ".seh_handlerdata");
74    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
75                                                                ".seh_pushreg");
76    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
77                                                               ".seh_setframe");
78    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
79                                                             ".seh_stackalloc");
80    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
81                                                                ".seh_savereg");
82    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
83                                                                ".seh_savexmm");
84    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
85                                                              ".seh_pushframe");
86    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
87                                                            ".seh_endprologue");
88    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
89  }
90
91  bool ParseSectionDirectiveText(StringRef, SMLoc) {
92    return ParseSectionSwitch(".text",
93                              COFF::IMAGE_SCN_CNT_CODE
94                            | COFF::IMAGE_SCN_MEM_EXECUTE
95                            | COFF::IMAGE_SCN_MEM_READ,
96                              SectionKind::getText());
97  }
98  bool ParseSectionDirectiveData(StringRef, SMLoc) {
99    return ParseSectionSwitch(".data",
100                              COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
101                            | COFF::IMAGE_SCN_MEM_READ
102                            | COFF::IMAGE_SCN_MEM_WRITE,
103                              SectionKind::getDataRel());
104  }
105  bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
106    return ParseSectionSwitch(".bss",
107                              COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
108                            | COFF::IMAGE_SCN_MEM_READ
109                            | COFF::IMAGE_SCN_MEM_WRITE,
110                              SectionKind::getBSS());
111  }
112
113  bool ParseDirectiveSection(StringRef, SMLoc);
114  bool ParseDirectiveDef(StringRef, SMLoc);
115  bool ParseDirectiveScl(StringRef, SMLoc);
116  bool ParseDirectiveType(StringRef, SMLoc);
117  bool ParseDirectiveEndef(StringRef, SMLoc);
118  bool ParseDirectiveSecRel32(StringRef, SMLoc);
119  bool ParseDirectiveSecIdx(StringRef, SMLoc);
120  bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
121                               const MCSectionCOFF *&Assoc);
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 (unsigned i = 0; i < FlagsString.size(); ++i) {
174    switch (FlagsString[i]) {
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, "",
296                            COFF::IMAGE_COMDAT_SELECT_ANY, nullptr);
297}
298
299bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
300                                       unsigned Characteristics,
301                                       SectionKind Kind,
302                                       StringRef COMDATSymName,
303                                       COFF::COMDATType Type,
304                                       const MCSectionCOFF *Assoc) {
305  if (getLexer().isNot(AsmToken::EndOfStatement))
306    return TokError("unexpected token in section switching directive");
307  Lex();
308
309  getStreamer().SwitchSection(getContext().getCOFFSection(
310      Section, Characteristics, Kind, COMDATSymName, Type, Assoc));
311
312  return false;
313}
314
315bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
316  if (!getLexer().is(AsmToken::Identifier))
317    return true;
318
319  SectionName = getTok().getIdentifier();
320  Lex();
321  return false;
322}
323
324// .section name [, "flags"] [, identifier [ identifier ], identifier]
325//
326// Supported flags:
327//   a: Ignored.
328//   b: BSS section (uninitialized data)
329//   d: data section (initialized data)
330//   n: Discardable section
331//   r: Readable section
332//   s: Shared section
333//   w: Writable section
334//   x: Executable section
335//   y: Not-readable section (clears 'r')
336//
337// Subsections are not supported.
338bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
339  StringRef SectionName;
340
341  if (ParseSectionName(SectionName))
342    return TokError("expected identifier in directive");
343
344  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
345                   COFF::IMAGE_SCN_MEM_READ |
346                   COFF::IMAGE_SCN_MEM_WRITE;
347
348  if (getLexer().is(AsmToken::Comma)) {
349    Lex();
350
351    if (getLexer().isNot(AsmToken::String))
352      return TokError("expected string in directive");
353
354    StringRef FlagsStr = getTok().getStringContents();
355    Lex();
356
357    if (ParseSectionFlags(FlagsStr, &Flags))
358      return true;
359  }
360
361  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
362  const MCSectionCOFF *Assoc = nullptr;
363  StringRef COMDATSymName;
364  if (getLexer().is(AsmToken::Comma)) {
365    Lex();
366
367    Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
368
369    if (parseCOMDATTypeAndAssoc(Type, Assoc))
370      return true;
371
372    if (getLexer().isNot(AsmToken::Comma))
373      return TokError("expected comma in directive");
374    Lex();
375
376    if (getParser().parseIdentifier(COMDATSymName))
377      return TokError("expected identifier in directive");
378  }
379
380  if (getLexer().isNot(AsmToken::EndOfStatement))
381    return TokError("unexpected token in directive");
382
383  SectionKind Kind = computeSectionKind(Flags);
384  ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc);
385  return false;
386}
387
388bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
389  StringRef SymbolName;
390
391  if (getParser().parseIdentifier(SymbolName))
392    return TokError("expected identifier in directive");
393
394  MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
395
396  getStreamer().BeginCOFFSymbolDef(Sym);
397
398  Lex();
399  return false;
400}
401
402bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
403  int64_t SymbolStorageClass;
404  if (getParser().parseAbsoluteExpression(SymbolStorageClass))
405    return true;
406
407  if (getLexer().isNot(AsmToken::EndOfStatement))
408    return TokError("unexpected token in directive");
409
410  Lex();
411  getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
412  return false;
413}
414
415bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
416  int64_t Type;
417  if (getParser().parseAbsoluteExpression(Type))
418    return true;
419
420  if (getLexer().isNot(AsmToken::EndOfStatement))
421    return TokError("unexpected token in directive");
422
423  Lex();
424  getStreamer().EmitCOFFSymbolType(Type);
425  return false;
426}
427
428bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
429  Lex();
430  getStreamer().EndCOFFSymbolDef();
431  return false;
432}
433
434bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
435  StringRef SymbolID;
436  if (getParser().parseIdentifier(SymbolID))
437    return TokError("expected identifier in directive");
438
439  if (getLexer().isNot(AsmToken::EndOfStatement))
440    return TokError("unexpected token in directive");
441
442  MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
443
444  Lex();
445  getStreamer().EmitCOFFSecRel32(Symbol);
446  return false;
447}
448
449bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
450  StringRef SymbolID;
451  if (getParser().parseIdentifier(SymbolID))
452    return TokError("expected identifier in directive");
453
454  if (getLexer().isNot(AsmToken::EndOfStatement))
455    return TokError("unexpected token in directive");
456
457  MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
458
459  Lex();
460  getStreamer().EmitCOFFSectionIndex(Symbol);
461  return false;
462}
463
464/// ::= [ identifier [ identifier ] ]
465bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
466                                            const MCSectionCOFF *&Assoc) {
467  StringRef TypeId = getTok().getIdentifier();
468
469  Type = StringSwitch<COFF::COMDATType>(TypeId)
470    .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
471    .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
472    .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
473    .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
474    .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
475    .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
476    .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
477    .Default((COFF::COMDATType)0);
478
479  if (Type == 0)
480    return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
481
482  Lex();
483
484  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
485    SMLoc Loc = getTok().getLoc();
486    StringRef AssocName;
487    if (ParseSectionName(AssocName))
488      return TokError("expected associated section name");
489
490    Assoc = static_cast<const MCSectionCOFF*>(
491                                        getContext().getCOFFSection(AssocName));
492    if (!Assoc)
493      return Error(Loc, "cannot associate unknown section '" + AssocName + "'");
494    if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT))
495      return Error(Loc, "associated section must be a COMDAT section");
496    if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
497      return Error(Loc, "associated section cannot be itself associative");
498  }
499
500  return false;
501}
502
503/// ParseDirectiveLinkOnce
504///  ::= .linkonce [ identifier [ identifier ] ]
505bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
506  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
507  const MCSectionCOFF *Assoc = nullptr;
508  if (getLexer().is(AsmToken::Identifier))
509    if (parseCOMDATTypeAndAssoc(Type, Assoc))
510      return true;
511
512  const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
513                                       getStreamer().getCurrentSection().first);
514
515
516  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
517    if (Assoc == Current)
518      return Error(Loc, "cannot associate a section with itself");
519  }
520
521  if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
522    return Error(Loc, Twine("section '") + Current->getSectionName() +
523                                                       "' is already linkonce");
524
525  Current->setSelection(Type, Assoc);
526
527  if (getLexer().isNot(AsmToken::EndOfStatement))
528    return TokError("unexpected token in directive");
529
530  return false;
531}
532
533bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
534  StringRef SymbolID;
535  if (getParser().parseIdentifier(SymbolID))
536    return true;
537
538  if (getLexer().isNot(AsmToken::EndOfStatement))
539    return TokError("unexpected token in directive");
540
541  MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
542
543  Lex();
544  getStreamer().EmitWin64EHStartProc(Symbol);
545  return false;
546}
547
548bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
549  Lex();
550  getStreamer().EmitWin64EHEndProc();
551  return false;
552}
553
554bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
555  Lex();
556  getStreamer().EmitWin64EHStartChained();
557  return false;
558}
559
560bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
561  Lex();
562  getStreamer().EmitWin64EHEndChained();
563  return false;
564}
565
566bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
567  StringRef SymbolID;
568  if (getParser().parseIdentifier(SymbolID))
569    return true;
570
571  if (getLexer().isNot(AsmToken::Comma))
572    return TokError("you must specify one or both of @unwind or @except");
573  Lex();
574  bool unwind = false, except = false;
575  if (ParseAtUnwindOrAtExcept(unwind, except))
576    return true;
577  if (getLexer().is(AsmToken::Comma)) {
578    Lex();
579    if (ParseAtUnwindOrAtExcept(unwind, except))
580      return true;
581  }
582  if (getLexer().isNot(AsmToken::EndOfStatement))
583    return TokError("unexpected token in directive");
584
585  MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
586
587  Lex();
588  getStreamer().EmitWin64EHHandler(handler, unwind, except);
589  return false;
590}
591
592bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
593  Lex();
594  getStreamer().EmitWin64EHHandlerData();
595  return false;
596}
597
598bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
599  unsigned Reg;
600  if (ParseSEHRegisterNumber(Reg))
601    return true;
602
603  if (getLexer().isNot(AsmToken::EndOfStatement))
604    return TokError("unexpected token in directive");
605
606  Lex();
607  getStreamer().EmitWin64EHPushReg(Reg);
608  return false;
609}
610
611bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
612  unsigned Reg;
613  int64_t Off;
614  if (ParseSEHRegisterNumber(Reg))
615    return true;
616  if (getLexer().isNot(AsmToken::Comma))
617    return TokError("you must specify a stack pointer offset");
618
619  Lex();
620  SMLoc startLoc = getLexer().getLoc();
621  if (getParser().parseAbsoluteExpression(Off))
622    return true;
623
624  if (Off & 0x0F)
625    return Error(startLoc, "offset is not a multiple of 16");
626
627  if (getLexer().isNot(AsmToken::EndOfStatement))
628    return TokError("unexpected token in directive");
629
630  Lex();
631  getStreamer().EmitWin64EHSetFrame(Reg, Off);
632  return false;
633}
634
635bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
636  int64_t Size;
637  SMLoc startLoc = getLexer().getLoc();
638  if (getParser().parseAbsoluteExpression(Size))
639    return true;
640
641  if (Size & 7)
642    return Error(startLoc, "size is not a multiple of 8");
643
644  if (getLexer().isNot(AsmToken::EndOfStatement))
645    return TokError("unexpected token in directive");
646
647  Lex();
648  getStreamer().EmitWin64EHAllocStack(Size);
649  return false;
650}
651
652bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
653  unsigned Reg;
654  int64_t Off;
655  if (ParseSEHRegisterNumber(Reg))
656    return true;
657  if (getLexer().isNot(AsmToken::Comma))
658    return TokError("you must specify an offset on the stack");
659
660  Lex();
661  SMLoc startLoc = getLexer().getLoc();
662  if (getParser().parseAbsoluteExpression(Off))
663    return true;
664
665  if (Off & 7)
666    return Error(startLoc, "size is not a multiple of 8");
667
668  if (getLexer().isNot(AsmToken::EndOfStatement))
669    return TokError("unexpected token in directive");
670
671  Lex();
672  // FIXME: Err on %xmm* registers
673  getStreamer().EmitWin64EHSaveReg(Reg, Off);
674  return false;
675}
676
677// FIXME: This method is inherently x86-specific. It should really be in the
678// x86 backend.
679bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
680  unsigned Reg;
681  int64_t Off;
682  if (ParseSEHRegisterNumber(Reg))
683    return true;
684  if (getLexer().isNot(AsmToken::Comma))
685    return TokError("you must specify an offset on the stack");
686
687  Lex();
688  SMLoc startLoc = getLexer().getLoc();
689  if (getParser().parseAbsoluteExpression(Off))
690    return true;
691
692  if (getLexer().isNot(AsmToken::EndOfStatement))
693    return TokError("unexpected token in directive");
694
695  if (Off & 0x0F)
696    return Error(startLoc, "offset is not a multiple of 16");
697
698  Lex();
699  // FIXME: Err on non-%xmm* registers
700  getStreamer().EmitWin64EHSaveXMM(Reg, Off);
701  return false;
702}
703
704bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
705  bool Code = false;
706  StringRef CodeID;
707  if (getLexer().is(AsmToken::At)) {
708    SMLoc startLoc = getLexer().getLoc();
709    Lex();
710    if (!getParser().parseIdentifier(CodeID)) {
711      if (CodeID != "code")
712        return Error(startLoc, "expected @code");
713      Code = true;
714    }
715  }
716
717  if (getLexer().isNot(AsmToken::EndOfStatement))
718    return TokError("unexpected token in directive");
719
720  Lex();
721  getStreamer().EmitWin64EHPushFrame(Code);
722  return false;
723}
724
725bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
726  Lex();
727  getStreamer().EmitWin64EHEndProlog();
728  return false;
729}
730
731bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
732  StringRef identifier;
733  if (getLexer().isNot(AsmToken::At))
734    return TokError("a handler attribute must begin with '@'");
735  SMLoc startLoc = getLexer().getLoc();
736  Lex();
737  if (getParser().parseIdentifier(identifier))
738    return Error(startLoc, "expected @unwind or @except");
739  if (identifier == "unwind")
740    unwind = true;
741  else if (identifier == "except")
742    except = true;
743  else
744    return Error(startLoc, "expected @unwind or @except");
745  return false;
746}
747
748bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
749  SMLoc startLoc = getLexer().getLoc();
750  if (getLexer().is(AsmToken::Percent)) {
751    const MCRegisterInfo *MRI = getContext().getRegisterInfo();
752    SMLoc endLoc;
753    unsigned LLVMRegNo;
754    if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
755      return true;
756
757#if 0
758    // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
759    // violation so this validation code is disabled.
760
761    // Check that this is a non-volatile register.
762    const unsigned *NVRegs = TAI.getCalleeSavedRegs();
763    unsigned i;
764    for (i = 0; NVRegs[i] != 0; ++i)
765      if (NVRegs[i] == LLVMRegNo)
766        break;
767    if (NVRegs[i] == 0)
768      return Error(startLoc, "expected non-volatile register");
769#endif
770
771    int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
772    if (SEHRegNo < 0)
773      return Error(startLoc,"register can't be represented in SEH unwind info");
774    RegNo = SEHRegNo;
775  }
776  else {
777    int64_t n;
778    if (getParser().parseAbsoluteExpression(n))
779      return true;
780    if (n > 15)
781      return Error(startLoc, "register number is too high");
782    RegNo = n;
783  }
784
785  return false;
786}
787
788namespace llvm {
789
790MCAsmParserExtension *createCOFFAsmParser() {
791  return new COFFAsmParser;
792}
793
794}
795