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