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/MCParser/MCAsmLexer.h"
17#include "llvm/MC/MCParser/MCAsmParserExtension.h"
18#include "llvm/MC/MCSectionCOFF.h"
19#include "llvm/MC/MCStreamer.h"
20#include "llvm/MC/SectionKind.h"
21#include "llvm/Support/SMLoc.h"
22#include <cassert>
23#include <cstdint>
24#include <limits>
25#include <utility>
26
27using namespace llvm;
28
29namespace {
30
31class COFFAsmParser : public MCAsmParserExtension {
32  template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
33  void addDirectiveHandler(StringRef Directive) {
34    MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
35        this, HandleDirective<COFFAsmParser, HandlerMethod>);
36    getParser().addDirectiveHandler(Directive, Handler);
37  }
38
39  bool ParseSectionSwitch(StringRef Section,
40                          unsigned Characteristics,
41                          SectionKind Kind);
42
43  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
44                          SectionKind Kind, StringRef COMDATSymName,
45                          COFF::COMDATType Type);
46
47  bool ParseSectionName(StringRef &SectionName);
48  bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
49                         unsigned *Flags);
50
51  void Initialize(MCAsmParser &Parser) override {
52    // Call the base implementation.
53    MCAsmParserExtension::Initialize(Parser);
54
55    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
56    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
57    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
58    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
59    addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
60    addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
61    addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
62    addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
63    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
64    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
65    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
66    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
67    addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
68    addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
69    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
70    addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
71
72    // Win64 EH directives.
73    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
74                                                                   ".seh_proc");
75    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
76                                                                ".seh_endproc");
77    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc>(
78                                                                ".seh_endfunclet");
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  bool ParseDirectiveCGProfile(StringRef, SMLoc);
129
130  // Win64 EH directives.
131  bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
132  bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
133  bool ParseSEHDirectiveEndFuncletOrFunc(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 ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
143
144public:
145  COFFAsmParser() = default;
146};
147
148} // end anonymous namespace.
149
150static SectionKind computeSectionKind(unsigned Flags) {
151  if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
152    return SectionKind::getText();
153  if (Flags & COFF::IMAGE_SCN_MEM_READ &&
154      (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
155    return SectionKind::getReadOnly();
156  return SectionKind::getData();
157}
158
159bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
160                                      StringRef FlagsString, unsigned *Flags) {
161  enum {
162    None = 0,
163    Alloc = 1 << 0,
164    Code = 1 << 1,
165    Load = 1 << 2,
166    InitData = 1 << 3,
167    Shared = 1 << 4,
168    NoLoad = 1 << 5,
169    NoRead = 1 << 6,
170    NoWrite = 1 << 7,
171    Discardable = 1 << 8,
172    Info = 1 << 9,
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    case 'i': // info
243      SecFlags |= Info;
244      break;
245
246    default:
247      return TokError("unknown flag");
248    }
249  }
250
251  *Flags = 0;
252
253  if (SecFlags == None)
254    SecFlags = InitData;
255
256  if (SecFlags & Code)
257    *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
258  if (SecFlags & InitData)
259    *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
260  if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
261    *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
262  if (SecFlags & NoLoad)
263    *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
264  if ((SecFlags & Discardable) ||
265      MCSectionCOFF::isImplicitlyDiscardable(SectionName))
266    *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
267  if ((SecFlags & NoRead) == 0)
268    *Flags |= COFF::IMAGE_SCN_MEM_READ;
269  if ((SecFlags & NoWrite) == 0)
270    *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
271  if (SecFlags & Shared)
272    *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
273  if (SecFlags & Info)
274    *Flags |= COFF::IMAGE_SCN_LNK_INFO;
275
276  return false;
277}
278
279/// ParseDirectiveSymbolAttribute
280///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
281bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
282  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
283    .Case(".weak", MCSA_Weak)
284    .Default(MCSA_Invalid);
285  assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
286  if (getLexer().isNot(AsmToken::EndOfStatement)) {
287    while (true) {
288      StringRef Name;
289
290      if (getParser().parseIdentifier(Name))
291        return TokError("expected identifier in directive");
292
293      MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
294
295      getStreamer().emitSymbolAttribute(Sym, Attr);
296
297      if (getLexer().is(AsmToken::EndOfStatement))
298        break;
299
300      if (getLexer().isNot(AsmToken::Comma))
301        return TokError("unexpected token in directive");
302      Lex();
303    }
304  }
305
306  Lex();
307  return false;
308}
309
310bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) {
311  return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc);
312}
313
314bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
315                                       unsigned Characteristics,
316                                       SectionKind Kind) {
317  return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
318}
319
320bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
321                                       unsigned Characteristics,
322                                       SectionKind Kind,
323                                       StringRef COMDATSymName,
324                                       COFF::COMDATType Type) {
325  if (getLexer().isNot(AsmToken::EndOfStatement))
326    return TokError("unexpected token in section switching directive");
327  Lex();
328
329  getStreamer().switchSection(getContext().getCOFFSection(
330      Section, Characteristics, Kind, COMDATSymName, Type));
331
332  return false;
333}
334
335bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
336  if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String))
337    return true;
338
339  SectionName = getTok().getIdentifier();
340  Lex();
341  return false;
342}
343
344// .section name [, "flags"] [, identifier [ identifier ], identifier]
345//
346// Supported flags:
347//   a: Ignored.
348//   b: BSS section (uninitialized data)
349//   d: data section (initialized data)
350//   n: "noload" section (removed by linker)
351//   D: Discardable section
352//   r: Readable section
353//   s: Shared section
354//   w: Writable section
355//   x: Executable section
356//   y: Not-readable section (clears 'r')
357//
358// Subsections are not supported.
359bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
360  StringRef SectionName;
361
362  if (ParseSectionName(SectionName))
363    return TokError("expected identifier in directive");
364
365  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
366                   COFF::IMAGE_SCN_MEM_READ |
367                   COFF::IMAGE_SCN_MEM_WRITE;
368
369  if (getLexer().is(AsmToken::Comma)) {
370    Lex();
371
372    if (getLexer().isNot(AsmToken::String))
373      return TokError("expected string in directive");
374
375    StringRef FlagsStr = getTok().getStringContents();
376    Lex();
377
378    if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
379      return true;
380  }
381
382  COFF::COMDATType Type = (COFF::COMDATType)0;
383  StringRef COMDATSymName;
384  if (getLexer().is(AsmToken::Comma)) {
385    Type = COFF::IMAGE_COMDAT_SELECT_ANY;
386    Lex();
387
388    Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
389
390    if (!getLexer().is(AsmToken::Identifier))
391      return TokError("expected comdat type such as 'discard' or 'largest' "
392                      "after protection bits");
393
394    if (parseCOMDATType(Type))
395      return true;
396
397    if (getLexer().isNot(AsmToken::Comma))
398      return TokError("expected comma in directive");
399    Lex();
400
401    if (getParser().parseIdentifier(COMDATSymName))
402      return TokError("expected identifier in directive");
403  }
404
405  if (getLexer().isNot(AsmToken::EndOfStatement))
406    return TokError("unexpected token in directive");
407
408  SectionKind Kind = computeSectionKind(Flags);
409  if (Kind.isText()) {
410    const Triple &T = getContext().getTargetTriple();
411    if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
412      Flags |= COFF::IMAGE_SCN_MEM_16BIT;
413  }
414  ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
415  return false;
416}
417
418bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
419  StringRef SymbolName;
420
421  if (getParser().parseIdentifier(SymbolName))
422    return TokError("expected identifier in directive");
423
424  MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
425
426  getStreamer().beginCOFFSymbolDef(Sym);
427
428  Lex();
429  return false;
430}
431
432bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
433  int64_t SymbolStorageClass;
434  if (getParser().parseAbsoluteExpression(SymbolStorageClass))
435    return true;
436
437  if (getLexer().isNot(AsmToken::EndOfStatement))
438    return TokError("unexpected token in directive");
439
440  Lex();
441  getStreamer().emitCOFFSymbolStorageClass(SymbolStorageClass);
442  return false;
443}
444
445bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
446  int64_t Type;
447  if (getParser().parseAbsoluteExpression(Type))
448    return true;
449
450  if (getLexer().isNot(AsmToken::EndOfStatement))
451    return TokError("unexpected token in directive");
452
453  Lex();
454  getStreamer().emitCOFFSymbolType(Type);
455  return false;
456}
457
458bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
459  Lex();
460  getStreamer().endCOFFSymbolDef();
461  return false;
462}
463
464bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
465  StringRef SymbolID;
466  if (getParser().parseIdentifier(SymbolID))
467    return TokError("expected identifier in directive");
468
469  int64_t Offset = 0;
470  SMLoc OffsetLoc;
471  if (getLexer().is(AsmToken::Plus)) {
472    OffsetLoc = getLexer().getLoc();
473    if (getParser().parseAbsoluteExpression(Offset))
474      return true;
475  }
476
477  if (getLexer().isNot(AsmToken::EndOfStatement))
478    return TokError("unexpected token in directive");
479
480  if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
481    return Error(
482        OffsetLoc,
483        "invalid '.secrel32' directive offset, can't be less "
484        "than zero or greater than std::numeric_limits<uint32_t>::max()");
485
486  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
487
488  Lex();
489  getStreamer().emitCOFFSecRel32(Symbol, Offset);
490  return false;
491}
492
493bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
494  auto parseOp = [&]() -> bool {
495    StringRef SymbolID;
496    if (getParser().parseIdentifier(SymbolID))
497      return TokError("expected identifier in directive");
498
499    int64_t Offset = 0;
500    SMLoc OffsetLoc;
501    if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
502      OffsetLoc = getLexer().getLoc();
503      if (getParser().parseAbsoluteExpression(Offset))
504        return true;
505    }
506
507    if (Offset < std::numeric_limits<int32_t>::min() ||
508        Offset > std::numeric_limits<int32_t>::max())
509      return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
510                              "than -2147483648 or greater than "
511                              "2147483647");
512
513    MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
514
515    getStreamer().emitCOFFImgRel32(Symbol, Offset);
516    return false;
517  };
518
519  if (getParser().parseMany(parseOp))
520    return addErrorSuffix(" in directive");
521  return false;
522}
523
524bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
525  StringRef SymbolID;
526  if (getParser().parseIdentifier(SymbolID))
527    return TokError("expected identifier in directive");
528
529  if (getLexer().isNot(AsmToken::EndOfStatement))
530    return TokError("unexpected token in directive");
531
532  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
533
534  Lex();
535  getStreamer().emitCOFFSafeSEH(Symbol);
536  return false;
537}
538
539bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
540  StringRef SymbolID;
541  if (getParser().parseIdentifier(SymbolID))
542    return TokError("expected identifier in directive");
543
544  if (getLexer().isNot(AsmToken::EndOfStatement))
545    return TokError("unexpected token in directive");
546
547  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
548
549  Lex();
550  getStreamer().emitCOFFSectionIndex(Symbol);
551  return false;
552}
553
554bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
555  StringRef SymbolID;
556  if (getParser().parseIdentifier(SymbolID))
557    return TokError("expected identifier in directive");
558
559  if (getLexer().isNot(AsmToken::EndOfStatement))
560    return TokError("unexpected token in directive");
561
562  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
563
564  Lex();
565  getStreamer().emitCOFFSymbolIndex(Symbol);
566  return false;
567}
568
569/// ::= [ identifier ]
570bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
571  StringRef TypeId = getTok().getIdentifier();
572
573  Type = StringSwitch<COFF::COMDATType>(TypeId)
574    .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
575    .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
576    .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
577    .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
578    .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
579    .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
580    .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
581    .Default((COFF::COMDATType)0);
582
583  if (Type == 0)
584    return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
585
586  Lex();
587
588  return false;
589}
590
591/// ParseDirectiveLinkOnce
592///  ::= .linkonce [ identifier ]
593bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
594  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
595  if (getLexer().is(AsmToken::Identifier))
596    if (parseCOMDATType(Type))
597      return true;
598
599  const MCSectionCOFF *Current =
600      static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
601
602  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
603    return Error(Loc, "cannot make section associative with .linkonce");
604
605  if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
606    return Error(Loc, Twine("section '") + Current->getName() +
607                          "' is already linkonce");
608
609  Current->setSelection(Type);
610
611  if (getLexer().isNot(AsmToken::EndOfStatement))
612    return TokError("unexpected token in directive");
613
614  return false;
615}
616
617bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
618  StringRef SymbolID;
619  if (getParser().parseIdentifier(SymbolID))
620    return true;
621
622  if (getLexer().isNot(AsmToken::EndOfStatement))
623    return TokError("unexpected token in directive");
624
625  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
626
627  Lex();
628  getStreamer().emitWinCFIStartProc(Symbol, Loc);
629  return false;
630}
631
632bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
633  Lex();
634  getStreamer().emitWinCFIEndProc(Loc);
635  return false;
636}
637
638bool COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) {
639  Lex();
640  getStreamer().emitWinCFIFuncletOrFuncEnd(Loc);
641  return false;
642}
643
644bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
645  Lex();
646  getStreamer().emitWinCFIStartChained(Loc);
647  return false;
648}
649
650bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
651  Lex();
652  getStreamer().emitWinCFIEndChained(Loc);
653  return false;
654}
655
656bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
657  StringRef SymbolID;
658  if (getParser().parseIdentifier(SymbolID))
659    return true;
660
661  if (getLexer().isNot(AsmToken::Comma))
662    return TokError("you must specify one or both of @unwind or @except");
663  Lex();
664  bool unwind = false, except = false;
665  if (ParseAtUnwindOrAtExcept(unwind, except))
666    return true;
667  if (getLexer().is(AsmToken::Comma)) {
668    Lex();
669    if (ParseAtUnwindOrAtExcept(unwind, except))
670      return true;
671  }
672  if (getLexer().isNot(AsmToken::EndOfStatement))
673    return TokError("unexpected token in directive");
674
675  MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
676
677  Lex();
678  getStreamer().emitWinEHHandler(handler, unwind, except, Loc);
679  return false;
680}
681
682bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
683  Lex();
684  getStreamer().emitWinEHHandlerData();
685  return false;
686}
687
688bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
689  int64_t Size;
690  if (getParser().parseAbsoluteExpression(Size))
691    return true;
692
693  if (getLexer().isNot(AsmToken::EndOfStatement))
694    return TokError("unexpected token in directive");
695
696  Lex();
697  getStreamer().emitWinCFIAllocStack(Size, Loc);
698  return false;
699}
700
701bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
702  Lex();
703  getStreamer().emitWinCFIEndProlog(Loc);
704  return false;
705}
706
707bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
708  StringRef identifier;
709  if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))
710    return TokError("a handler attribute must begin with '@' or '%'");
711  SMLoc startLoc = getLexer().getLoc();
712  Lex();
713  if (getParser().parseIdentifier(identifier))
714    return Error(startLoc, "expected @unwind or @except");
715  if (identifier == "unwind")
716    unwind = true;
717  else if (identifier == "except")
718    except = true;
719  else
720    return Error(startLoc, "expected @unwind or @except");
721  return false;
722}
723
724namespace llvm {
725
726MCAsmParserExtension *createCOFFAsmParser() {
727  return new COFFAsmParser;
728}
729
730} // end namespace llvm
731