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