COFFAsmParser.cpp revision 360784
1//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ADT/StringRef.h"
10#include "llvm/ADT/StringSwitch.h"
11#include "llvm/ADT/Triple.h"
12#include "llvm/ADT/Twine.h"
13#include "llvm/BinaryFormat/COFF.h"
14#include "llvm/MC/MCContext.h"
15#include "llvm/MC/MCDirectives.h"
16#include "llvm/MC/MCObjectFileInfo.h"
17#include "llvm/MC/MCParser/MCAsmLexer.h"
18#include "llvm/MC/MCParser/MCAsmParserExtension.h"
19#include "llvm/MC/MCParser/MCTargetAsmParser.h"
20#include "llvm/MC/MCRegisterInfo.h"
21#include "llvm/MC/MCSectionCOFF.h"
22#include "llvm/MC/MCStreamer.h"
23#include "llvm/MC/SectionKind.h"
24#include "llvm/Support/SMLoc.h"
25#include <cassert>
26#include <cstdint>
27#include <limits>
28#include <utility>
29
30using namespace llvm;
31
32namespace {
33
34class COFFAsmParser : public MCAsmParserExtension {
35  template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
36  void addDirectiveHandler(StringRef Directive) {
37    MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
38        this, HandleDirective<COFFAsmParser, HandlerMethod>);
39    getParser().addDirectiveHandler(Directive, Handler);
40  }
41
42  bool ParseSectionSwitch(StringRef Section,
43                          unsigned Characteristics,
44                          SectionKind Kind);
45
46  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47                          SectionKind Kind, StringRef COMDATSymName,
48                          COFF::COMDATType Type);
49
50  bool ParseSectionName(StringRef &SectionName);
51  bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
52                         unsigned *Flags);
53
54  void Initialize(MCAsmParser &Parser) override {
55    // Call the base implementation.
56    MCAsmParserExtension::Initialize(Parser);
57
58    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
59    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
60    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
61    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
62    addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
63    addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
64    addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
65    addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
66    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
67    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
68    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
69    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
70    addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
71    addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
72    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
73
74    // Win64 EH directives.
75    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
76                                                                   ".seh_proc");
77    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
78                                                                ".seh_endproc");
79    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
80                                                           ".seh_startchained");
81    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
82                                                             ".seh_endchained");
83    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
84                                                                ".seh_handler");
85    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
86                                                            ".seh_handlerdata");
87    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
88                                                             ".seh_stackalloc");
89    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
90                                                            ".seh_endprologue");
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
101  bool ParseSectionDirectiveData(StringRef, SMLoc) {
102    return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
103                                           COFF::IMAGE_SCN_MEM_READ |
104                                           COFF::IMAGE_SCN_MEM_WRITE,
105                              SectionKind::getData());
106  }
107
108  bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
109    return ParseSectionSwitch(".bss",
110                              COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
111                            | COFF::IMAGE_SCN_MEM_READ
112                            | COFF::IMAGE_SCN_MEM_WRITE,
113                              SectionKind::getBSS());
114  }
115
116  bool ParseDirectiveSection(StringRef, SMLoc);
117  bool ParseDirectiveDef(StringRef, SMLoc);
118  bool ParseDirectiveScl(StringRef, SMLoc);
119  bool ParseDirectiveType(StringRef, SMLoc);
120  bool ParseDirectiveEndef(StringRef, SMLoc);
121  bool ParseDirectiveSecRel32(StringRef, SMLoc);
122  bool ParseDirectiveSecIdx(StringRef, SMLoc);
123  bool ParseDirectiveSafeSEH(StringRef, SMLoc);
124  bool ParseDirectiveSymIdx(StringRef, SMLoc);
125  bool parseCOMDATType(COFF::COMDATType &Type);
126  bool ParseDirectiveLinkOnce(StringRef, SMLoc);
127  bool ParseDirectiveRVA(StringRef, SMLoc);
128
129  // Win64 EH directives.
130  bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
131  bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
132  bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
133  bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
134  bool ParseSEHDirectiveHandler(StringRef, SMLoc);
135  bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
136  bool ParseSEHDirectiveAllocStack(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);
142
143public:
144  COFFAsmParser() = default;
145};
146
147} // end anonymous 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 SectionName,
159                                      StringRef FlagsString, unsigned *Flags) {
160  enum {
161    None        = 0,
162    Alloc       = 1 << 0,
163    Code        = 1 << 1,
164    Load        = 1 << 2,
165    InitData    = 1 << 3,
166    Shared      = 1 << 4,
167    NoLoad      = 1 << 5,
168    NoRead      = 1 << 6,
169    NoWrite     = 1 << 7,
170    Discardable = 1 << 8,
171  };
172
173  bool ReadOnlyRemoved = false;
174  unsigned SecFlags = None;
175
176  for (char FlagChar : FlagsString) {
177    switch (FlagChar) {
178    case 'a':
179      // Ignored.
180      break;
181
182    case 'b': // bss section
183      SecFlags |= Alloc;
184      if (SecFlags & InitData)
185        return TokError("conflicting section flags 'b' and 'd'.");
186      SecFlags &= ~Load;
187      break;
188
189    case 'd': // data section
190      SecFlags |= InitData;
191      if (SecFlags & Alloc)
192        return TokError("conflicting section flags 'b' and 'd'.");
193      SecFlags &= ~NoWrite;
194      if ((SecFlags & NoLoad) == 0)
195        SecFlags |= Load;
196      break;
197
198    case 'n': // section is not loaded
199      SecFlags |= NoLoad;
200      SecFlags &= ~Load;
201      break;
202
203    case 'D': // discardable
204      SecFlags |= Discardable;
205      break;
206
207    case 'r': // read-only
208      ReadOnlyRemoved = false;
209      SecFlags |= NoWrite;
210      if ((SecFlags & Code) == 0)
211        SecFlags |= InitData;
212      if ((SecFlags & NoLoad) == 0)
213        SecFlags |= Load;
214      break;
215
216    case 's': // shared section
217      SecFlags |= Shared | InitData;
218      SecFlags &= ~NoWrite;
219      if ((SecFlags & NoLoad) == 0)
220        SecFlags |= Load;
221      break;
222
223    case 'w': // writable
224      SecFlags &= ~NoWrite;
225      ReadOnlyRemoved = true;
226      break;
227
228    case 'x': // executable section
229      SecFlags |= Code;
230      if ((SecFlags & NoLoad) == 0)
231        SecFlags |= Load;
232      if (!ReadOnlyRemoved)
233        SecFlags |= NoWrite;
234      break;
235
236    case 'y': // not readable
237      SecFlags |= NoRead | NoWrite;
238      break;
239
240    default:
241      return TokError("unknown flag");
242    }
243  }
244
245  *Flags = 0;
246
247  if (SecFlags == None)
248    SecFlags = InitData;
249
250  if (SecFlags & Code)
251    *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
252  if (SecFlags & InitData)
253    *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
254  if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
255    *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
256  if (SecFlags & NoLoad)
257    *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
258  if ((SecFlags & Discardable) ||
259      MCSectionCOFF::isImplicitlyDiscardable(SectionName))
260    *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
261  if ((SecFlags & NoRead) == 0)
262    *Flags |= COFF::IMAGE_SCN_MEM_READ;
263  if ((SecFlags & NoWrite) == 0)
264    *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
265  if (SecFlags & Shared)
266    *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
267
268  return false;
269}
270
271/// ParseDirectiveSymbolAttribute
272///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
273bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
274  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
275    .Case(".weak", MCSA_Weak)
276    .Default(MCSA_Invalid);
277  assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
278  if (getLexer().isNot(AsmToken::EndOfStatement)) {
279    while (true) {
280      StringRef Name;
281
282      if (getParser().parseIdentifier(Name))
283        return TokError("expected identifier in directive");
284
285      MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
286
287      getStreamer().EmitSymbolAttribute(Sym, Attr);
288
289      if (getLexer().is(AsmToken::EndOfStatement))
290        break;
291
292      if (getLexer().isNot(AsmToken::Comma))
293        return TokError("unexpected token in directive");
294      Lex();
295    }
296  }
297
298  Lex();
299  return false;
300}
301
302bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
303                                       unsigned Characteristics,
304                                       SectionKind Kind) {
305  return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
306}
307
308bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
309                                       unsigned Characteristics,
310                                       SectionKind Kind,
311                                       StringRef COMDATSymName,
312                                       COFF::COMDATType Type) {
313  if (getLexer().isNot(AsmToken::EndOfStatement))
314    return TokError("unexpected token in section switching directive");
315  Lex();
316
317  getStreamer().SwitchSection(getContext().getCOFFSection(
318      Section, Characteristics, Kind, COMDATSymName, Type));
319
320  return false;
321}
322
323bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
324  if (!getLexer().is(AsmToken::Identifier))
325    return true;
326
327  SectionName = getTok().getIdentifier();
328  Lex();
329  return false;
330}
331
332// .section name [, "flags"] [, identifier [ identifier ], identifier]
333//
334// Supported flags:
335//   a: Ignored.
336//   b: BSS section (uninitialized data)
337//   d: data section (initialized data)
338//   n: "noload" section (removed by linker)
339//   D: Discardable section
340//   r: Readable section
341//   s: Shared section
342//   w: Writable section
343//   x: Executable section
344//   y: Not-readable section (clears 'r')
345//
346// Subsections are not supported.
347bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
348  StringRef SectionName;
349
350  if (ParseSectionName(SectionName))
351    return TokError("expected identifier in directive");
352
353  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
354                   COFF::IMAGE_SCN_MEM_READ |
355                   COFF::IMAGE_SCN_MEM_WRITE;
356
357  if (getLexer().is(AsmToken::Comma)) {
358    Lex();
359
360    if (getLexer().isNot(AsmToken::String))
361      return TokError("expected string in directive");
362
363    StringRef FlagsStr = getTok().getStringContents();
364    Lex();
365
366    if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
367      return true;
368  }
369
370  COFF::COMDATType Type = (COFF::COMDATType)0;
371  StringRef COMDATSymName;
372  if (getLexer().is(AsmToken::Comma)) {
373    Type = COFF::IMAGE_COMDAT_SELECT_ANY;
374    Lex();
375
376    Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
377
378    if (!getLexer().is(AsmToken::Identifier))
379      return TokError("expected comdat type such as 'discard' or 'largest' "
380                      "after protection bits");
381
382    if (parseCOMDATType(Type))
383      return true;
384
385    if (getLexer().isNot(AsmToken::Comma))
386      return TokError("expected comma in directive");
387    Lex();
388
389    if (getParser().parseIdentifier(COMDATSymName))
390      return TokError("expected identifier in directive");
391  }
392
393  if (getLexer().isNot(AsmToken::EndOfStatement))
394    return TokError("unexpected token in directive");
395
396  SectionKind Kind = computeSectionKind(Flags);
397  if (Kind.isText()) {
398    const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
399    if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
400      Flags |= COFF::IMAGE_SCN_MEM_16BIT;
401  }
402  ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
403  return false;
404}
405
406bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
407  StringRef SymbolName;
408
409  if (getParser().parseIdentifier(SymbolName))
410    return TokError("expected identifier in directive");
411
412  MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
413
414  getStreamer().BeginCOFFSymbolDef(Sym);
415
416  Lex();
417  return false;
418}
419
420bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
421  int64_t SymbolStorageClass;
422  if (getParser().parseAbsoluteExpression(SymbolStorageClass))
423    return true;
424
425  if (getLexer().isNot(AsmToken::EndOfStatement))
426    return TokError("unexpected token in directive");
427
428  Lex();
429  getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
430  return false;
431}
432
433bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
434  int64_t Type;
435  if (getParser().parseAbsoluteExpression(Type))
436    return true;
437
438  if (getLexer().isNot(AsmToken::EndOfStatement))
439    return TokError("unexpected token in directive");
440
441  Lex();
442  getStreamer().EmitCOFFSymbolType(Type);
443  return false;
444}
445
446bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
447  Lex();
448  getStreamer().EndCOFFSymbolDef();
449  return false;
450}
451
452bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
453  StringRef SymbolID;
454  if (getParser().parseIdentifier(SymbolID))
455    return TokError("expected identifier in directive");
456
457  int64_t Offset = 0;
458  SMLoc OffsetLoc;
459  if (getLexer().is(AsmToken::Plus)) {
460    OffsetLoc = getLexer().getLoc();
461    if (getParser().parseAbsoluteExpression(Offset))
462      return true;
463  }
464
465  if (getLexer().isNot(AsmToken::EndOfStatement))
466    return TokError("unexpected token in directive");
467
468  if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
469    return Error(
470        OffsetLoc,
471        "invalid '.secrel32' directive offset, can't be less "
472        "than zero or greater than std::numeric_limits<uint32_t>::max()");
473
474  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
475
476  Lex();
477  getStreamer().EmitCOFFSecRel32(Symbol, Offset);
478  return false;
479}
480
481bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
482  auto parseOp = [&]() -> bool {
483    StringRef SymbolID;
484    if (getParser().parseIdentifier(SymbolID))
485      return TokError("expected identifier in directive");
486
487    int64_t Offset = 0;
488    SMLoc OffsetLoc;
489    if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
490      OffsetLoc = getLexer().getLoc();
491      if (getParser().parseAbsoluteExpression(Offset))
492        return true;
493    }
494
495    if (Offset < std::numeric_limits<int32_t>::min() ||
496        Offset > std::numeric_limits<int32_t>::max())
497      return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
498                              "than -2147483648 or greater than "
499                              "2147483647");
500
501    MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
502
503    getStreamer().EmitCOFFImgRel32(Symbol, Offset);
504    return false;
505  };
506
507  if (getParser().parseMany(parseOp))
508    return addErrorSuffix(" in directive");
509  return false;
510}
511
512bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
513  StringRef SymbolID;
514  if (getParser().parseIdentifier(SymbolID))
515    return TokError("expected identifier in directive");
516
517  if (getLexer().isNot(AsmToken::EndOfStatement))
518    return TokError("unexpected token in directive");
519
520  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
521
522  Lex();
523  getStreamer().EmitCOFFSafeSEH(Symbol);
524  return false;
525}
526
527bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
528  StringRef SymbolID;
529  if (getParser().parseIdentifier(SymbolID))
530    return TokError("expected identifier in directive");
531
532  if (getLexer().isNot(AsmToken::EndOfStatement))
533    return TokError("unexpected token in directive");
534
535  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
536
537  Lex();
538  getStreamer().EmitCOFFSectionIndex(Symbol);
539  return false;
540}
541
542bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
543  StringRef SymbolID;
544  if (getParser().parseIdentifier(SymbolID))
545    return TokError("expected identifier in directive");
546
547  if (getLexer().isNot(AsmToken::EndOfStatement))
548    return TokError("unexpected token in directive");
549
550  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
551
552  Lex();
553  getStreamer().EmitCOFFSymbolIndex(Symbol);
554  return false;
555}
556
557/// ::= [ identifier ]
558bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
559  StringRef TypeId = getTok().getIdentifier();
560
561  Type = StringSwitch<COFF::COMDATType>(TypeId)
562    .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
563    .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
564    .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
565    .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
566    .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
567    .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
568    .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
569    .Default((COFF::COMDATType)0);
570
571  if (Type == 0)
572    return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
573
574  Lex();
575
576  return false;
577}
578
579/// ParseDirectiveLinkOnce
580///  ::= .linkonce [ identifier ]
581bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
582  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
583  if (getLexer().is(AsmToken::Identifier))
584    if (parseCOMDATType(Type))
585      return true;
586
587  const MCSectionCOFF *Current =
588      static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
589
590  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
591    return Error(Loc, "cannot make section associative with .linkonce");
592
593  if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
594    return Error(Loc, Twine("section '") + Current->getSectionName() +
595                                                       "' is already linkonce");
596
597  Current->setSelection(Type);
598
599  if (getLexer().isNot(AsmToken::EndOfStatement))
600    return TokError("unexpected token in directive");
601
602  return false;
603}
604
605bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
606  StringRef SymbolID;
607  if (getParser().parseIdentifier(SymbolID))
608    return true;
609
610  if (getLexer().isNot(AsmToken::EndOfStatement))
611    return TokError("unexpected token in directive");
612
613  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
614
615  Lex();
616  getStreamer().EmitWinCFIStartProc(Symbol, Loc);
617  return false;
618}
619
620bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
621  Lex();
622  getStreamer().EmitWinCFIEndProc(Loc);
623  return false;
624}
625
626bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
627  Lex();
628  getStreamer().EmitWinCFIStartChained(Loc);
629  return false;
630}
631
632bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
633  Lex();
634  getStreamer().EmitWinCFIEndChained(Loc);
635  return false;
636}
637
638bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
639  StringRef SymbolID;
640  if (getParser().parseIdentifier(SymbolID))
641    return true;
642
643  if (getLexer().isNot(AsmToken::Comma))
644    return TokError("you must specify one or both of @unwind or @except");
645  Lex();
646  bool unwind = false, except = false;
647  if (ParseAtUnwindOrAtExcept(unwind, except))
648    return true;
649  if (getLexer().is(AsmToken::Comma)) {
650    Lex();
651    if (ParseAtUnwindOrAtExcept(unwind, except))
652      return true;
653  }
654  if (getLexer().isNot(AsmToken::EndOfStatement))
655    return TokError("unexpected token in directive");
656
657  MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
658
659  Lex();
660  getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
661  return false;
662}
663
664bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
665  Lex();
666  getStreamer().EmitWinEHHandlerData();
667  return false;
668}
669
670bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
671  int64_t Size;
672  if (getParser().parseAbsoluteExpression(Size))
673    return true;
674
675  if (getLexer().isNot(AsmToken::EndOfStatement))
676    return TokError("unexpected token in directive");
677
678  Lex();
679  getStreamer().EmitWinCFIAllocStack(Size, Loc);
680  return false;
681}
682
683bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
684  Lex();
685  getStreamer().EmitWinCFIEndProlog(Loc);
686  return false;
687}
688
689bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
690  StringRef identifier;
691  if (getLexer().isNot(AsmToken::At))
692    return TokError("a handler attribute must begin with '@'");
693  SMLoc startLoc = getLexer().getLoc();
694  Lex();
695  if (getParser().parseIdentifier(identifier))
696    return Error(startLoc, "expected @unwind or @except");
697  if (identifier == "unwind")
698    unwind = true;
699  else if (identifier == "except")
700    except = true;
701  else
702    return Error(startLoc, "expected @unwind or @except");
703  return false;
704}
705
706namespace llvm {
707
708MCAsmParserExtension *createCOFFAsmParser() {
709  return new COFFAsmParser;
710}
711
712} // end namespace llvm
713