diff options
Diffstat (limited to 'llvm/lib/MC/MCParser/COFFAsmParser.cpp')
| -rw-r--r-- | llvm/lib/MC/MCParser/COFFAsmParser.cpp | 712 | 
1 files changed, 712 insertions, 0 deletions
diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 000000000000..06f8310ae061 --- /dev/null +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,712 @@ +//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Support/SMLoc.h" +#include <cassert> +#include <cstdint> +#include <limits> +#include <utility> + +using namespace llvm; + +namespace { + +class COFFAsmParser : public MCAsmParserExtension { +  template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> +  void addDirectiveHandler(StringRef Directive) { +    MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( +        this, HandleDirective<COFFAsmParser, HandlerMethod>); +    getParser().addDirectiveHandler(Directive, Handler); +  } + +  bool ParseSectionSwitch(StringRef Section, +                          unsigned Characteristics, +                          SectionKind Kind); + +  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, +                          SectionKind Kind, StringRef COMDATSymName, +                          COFF::COMDATType Type); + +  bool ParseSectionName(StringRef &SectionName); +  bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, +                         unsigned *Flags); + +  void Initialize(MCAsmParser &Parser) override { +    // Call the base implementation. +    MCAsmParserExtension::Initialize(Parser); + +    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); +    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); +    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); +    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + +    // Win64 EH directives. +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( +                                                                   ".seh_proc"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( +                                                                ".seh_endproc"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( +                                                           ".seh_startchained"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( +                                                             ".seh_endchained"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( +                                                                ".seh_handler"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( +                                                            ".seh_handlerdata"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( +                                                             ".seh_stackalloc"); +    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( +                                                            ".seh_endprologue"); +  } + +  bool ParseSectionDirectiveText(StringRef, SMLoc) { +    return ParseSectionSwitch(".text", +                              COFF::IMAGE_SCN_CNT_CODE +                            | COFF::IMAGE_SCN_MEM_EXECUTE +                            | COFF::IMAGE_SCN_MEM_READ, +                              SectionKind::getText()); +  } + +  bool ParseSectionDirectiveData(StringRef, SMLoc) { +    return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | +                                           COFF::IMAGE_SCN_MEM_READ | +                                           COFF::IMAGE_SCN_MEM_WRITE, +                              SectionKind::getData()); +  } + +  bool ParseSectionDirectiveBSS(StringRef, SMLoc) { +    return ParseSectionSwitch(".bss", +                              COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA +                            | COFF::IMAGE_SCN_MEM_READ +                            | COFF::IMAGE_SCN_MEM_WRITE, +                              SectionKind::getBSS()); +  } + +  bool ParseDirectiveSection(StringRef, SMLoc); +  bool ParseDirectiveDef(StringRef, SMLoc); +  bool ParseDirectiveScl(StringRef, SMLoc); +  bool ParseDirectiveType(StringRef, SMLoc); +  bool ParseDirectiveEndef(StringRef, SMLoc); +  bool ParseDirectiveSecRel32(StringRef, SMLoc); +  bool ParseDirectiveSecIdx(StringRef, SMLoc); +  bool ParseDirectiveSafeSEH(StringRef, SMLoc); +  bool ParseDirectiveSymIdx(StringRef, SMLoc); +  bool parseCOMDATType(COFF::COMDATType &Type); +  bool ParseDirectiveLinkOnce(StringRef, SMLoc); +  bool ParseDirectiveRVA(StringRef, SMLoc); + +  // Win64 EH directives. +  bool ParseSEHDirectiveStartProc(StringRef, SMLoc); +  bool ParseSEHDirectiveEndProc(StringRef, SMLoc); +  bool ParseSEHDirectiveStartChained(StringRef, SMLoc); +  bool ParseSEHDirectiveEndChained(StringRef, SMLoc); +  bool ParseSEHDirectiveHandler(StringRef, SMLoc); +  bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); +  bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); +  bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); + +  bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); +  bool ParseSEHRegisterNumber(unsigned &RegNo); +  bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); + +public: +  COFFAsmParser() = default; +}; + +} // end annonomous namespace. + +static SectionKind computeSectionKind(unsigned Flags) { +  if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) +    return SectionKind::getText(); +  if (Flags & COFF::IMAGE_SCN_MEM_READ && +      (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) +    return SectionKind::getReadOnly(); +  return SectionKind::getData(); +} + +bool COFFAsmParser::ParseSectionFlags(StringRef SectionName, +                                      StringRef FlagsString, unsigned *Flags) { +  enum { +    None        = 0, +    Alloc       = 1 << 0, +    Code        = 1 << 1, +    Load        = 1 << 2, +    InitData    = 1 << 3, +    Shared      = 1 << 4, +    NoLoad      = 1 << 5, +    NoRead      = 1 << 6, +    NoWrite     = 1 << 7, +    Discardable = 1 << 8, +  }; + +  bool ReadOnlyRemoved = false; +  unsigned SecFlags = None; + +  for (char FlagChar : FlagsString) { +    switch (FlagChar) { +    case 'a': +      // Ignored. +      break; + +    case 'b': // bss section +      SecFlags |= Alloc; +      if (SecFlags & InitData) +        return TokError("conflicting section flags 'b' and 'd'."); +      SecFlags &= ~Load; +      break; + +    case 'd': // data section +      SecFlags |= InitData; +      if (SecFlags & Alloc) +        return TokError("conflicting section flags 'b' and 'd'."); +      SecFlags &= ~NoWrite; +      if ((SecFlags & NoLoad) == 0) +        SecFlags |= Load; +      break; + +    case 'n': // section is not loaded +      SecFlags |= NoLoad; +      SecFlags &= ~Load; +      break; + +    case 'D': // discardable +      SecFlags |= Discardable; +      break; + +    case 'r': // read-only +      ReadOnlyRemoved = false; +      SecFlags |= NoWrite; +      if ((SecFlags & Code) == 0) +        SecFlags |= InitData; +      if ((SecFlags & NoLoad) == 0) +        SecFlags |= Load; +      break; + +    case 's': // shared section +      SecFlags |= Shared | InitData; +      SecFlags &= ~NoWrite; +      if ((SecFlags & NoLoad) == 0) +        SecFlags |= Load; +      break; + +    case 'w': // writable +      SecFlags &= ~NoWrite; +      ReadOnlyRemoved = true; +      break; + +    case 'x': // executable section +      SecFlags |= Code; +      if ((SecFlags & NoLoad) == 0) +        SecFlags |= Load; +      if (!ReadOnlyRemoved) +        SecFlags |= NoWrite; +      break; + +    case 'y': // not readable +      SecFlags |= NoRead | NoWrite; +      break; + +    default: +      return TokError("unknown flag"); +    } +  } + +  *Flags = 0; + +  if (SecFlags == None) +    SecFlags = InitData; + +  if (SecFlags & Code) +    *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; +  if (SecFlags & InitData) +    *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; +  if ((SecFlags & Alloc) && (SecFlags & Load) == 0) +    *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; +  if (SecFlags & NoLoad) +    *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; +  if ((SecFlags & Discardable) || +      MCSectionCOFF::isImplicitlyDiscardable(SectionName)) +    *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; +  if ((SecFlags & NoRead) == 0) +    *Flags |= COFF::IMAGE_SCN_MEM_READ; +  if ((SecFlags & NoWrite) == 0) +    *Flags |= COFF::IMAGE_SCN_MEM_WRITE; +  if (SecFlags & Shared) +    *Flags |= COFF::IMAGE_SCN_MEM_SHARED; + +  return false; +} + +/// ParseDirectiveSymbolAttribute +///  ::= { ".weak", ... } [ identifier ( , identifier )* ] +bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { +  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) +    .Case(".weak", MCSA_Weak) +    .Default(MCSA_Invalid); +  assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); +  if (getLexer().isNot(AsmToken::EndOfStatement)) { +    while (true) { +      StringRef Name; + +      if (getParser().parseIdentifier(Name)) +        return TokError("expected identifier in directive"); + +      MCSymbol *Sym = getContext().getOrCreateSymbol(Name); + +      getStreamer().EmitSymbolAttribute(Sym, Attr); + +      if (getLexer().is(AsmToken::EndOfStatement)) +        break; + +      if (getLexer().isNot(AsmToken::Comma)) +        return TokError("unexpected token in directive"); +      Lex(); +    } +  } + +  Lex(); +  return false; +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, +                                       unsigned Characteristics, +                                       SectionKind Kind) { +  return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0); +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, +                                       unsigned Characteristics, +                                       SectionKind Kind, +                                       StringRef COMDATSymName, +                                       COFF::COMDATType Type) { +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in section switching directive"); +  Lex(); + +  getStreamer().SwitchSection(getContext().getCOFFSection( +      Section, Characteristics, Kind, COMDATSymName, Type)); + +  return false; +} + +bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { +  if (!getLexer().is(AsmToken::Identifier)) +    return true; + +  SectionName = getTok().getIdentifier(); +  Lex(); +  return false; +} + +// .section name [, "flags"] [, identifier [ identifier ], identifier] +// +// Supported flags: +//   a: Ignored. +//   b: BSS section (uninitialized data) +//   d: data section (initialized data) +//   n: "noload" section (removed by linker) +//   D: Discardable section +//   r: Readable section +//   s: Shared section +//   w: Writable section +//   x: Executable section +//   y: Not-readable section (clears 'r') +// +// Subsections are not supported. +bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { +  StringRef SectionName; + +  if (ParseSectionName(SectionName)) +    return TokError("expected identifier in directive"); + +  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | +                   COFF::IMAGE_SCN_MEM_READ | +                   COFF::IMAGE_SCN_MEM_WRITE; + +  if (getLexer().is(AsmToken::Comma)) { +    Lex(); + +    if (getLexer().isNot(AsmToken::String)) +      return TokError("expected string in directive"); + +    StringRef FlagsStr = getTok().getStringContents(); +    Lex(); + +    if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) +      return true; +  } + +  COFF::COMDATType Type = (COFF::COMDATType)0; +  StringRef COMDATSymName; +  if (getLexer().is(AsmToken::Comma)) { +    Type = COFF::IMAGE_COMDAT_SELECT_ANY; +    Lex(); + +    Flags |= COFF::IMAGE_SCN_LNK_COMDAT; + +    if (!getLexer().is(AsmToken::Identifier)) +      return TokError("expected comdat type such as 'discard' or 'largest' " +                      "after protection bits"); + +    if (parseCOMDATType(Type)) +      return true; + +    if (getLexer().isNot(AsmToken::Comma)) +      return TokError("expected comma in directive"); +    Lex(); + +    if (getParser().parseIdentifier(COMDATSymName)) +      return TokError("expected identifier in directive"); +  } + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  SectionKind Kind = computeSectionKind(Flags); +  if (Kind.isText()) { +    const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); +    if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) +      Flags |= COFF::IMAGE_SCN_MEM_16BIT; +  } +  ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type); +  return false; +} + +bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { +  StringRef SymbolName; + +  if (getParser().parseIdentifier(SymbolName)) +    return TokError("expected identifier in directive"); + +  MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); + +  getStreamer().BeginCOFFSymbolDef(Sym); + +  Lex(); +  return false; +} + +bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { +  int64_t SymbolStorageClass; +  if (getParser().parseAbsoluteExpression(SymbolStorageClass)) +    return true; + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  Lex(); +  getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); +  return false; +} + +bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { +  int64_t Type; +  if (getParser().parseAbsoluteExpression(Type)) +    return true; + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  Lex(); +  getStreamer().EmitCOFFSymbolType(Type); +  return false; +} + +bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { +  Lex(); +  getStreamer().EndCOFFSymbolDef(); +  return false; +} + +bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return TokError("expected identifier in directive"); + +  int64_t Offset = 0; +  SMLoc OffsetLoc; +  if (getLexer().is(AsmToken::Plus)) { +    OffsetLoc = getLexer().getLoc(); +    if (getParser().parseAbsoluteExpression(Offset)) +      return true; +  } + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) +    return Error( +        OffsetLoc, +        "invalid '.secrel32' directive offset, can't be less " +        "than zero or greater than std::numeric_limits<uint32_t>::max()"); + +  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitCOFFSecRel32(Symbol, Offset); +  return false; +} + +bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { +  auto parseOp = [&]() -> bool { +    StringRef SymbolID; +    if (getParser().parseIdentifier(SymbolID)) +      return TokError("expected identifier in directive"); + +    int64_t Offset = 0; +    SMLoc OffsetLoc; +    if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { +      OffsetLoc = getLexer().getLoc(); +      if (getParser().parseAbsoluteExpression(Offset)) +        return true; +    } + +    if (Offset < std::numeric_limits<int32_t>::min() || +        Offset > std::numeric_limits<int32_t>::max()) +      return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " +                              "than -2147483648 or greater than " +                              "2147483647"); + +    MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +    getStreamer().EmitCOFFImgRel32(Symbol, Offset); +    return false; +  }; + +  if (getParser().parseMany(parseOp)) +    return addErrorSuffix(" in directive"); +  return false; +} + +bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return TokError("expected identifier in directive"); + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitCOFFSafeSEH(Symbol); +  return false; +} + +bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return TokError("expected identifier in directive"); + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitCOFFSectionIndex(Symbol); +  return false; +} + +bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return TokError("expected identifier in directive"); + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitCOFFSymbolIndex(Symbol); +  return false; +} + +/// ::= [ identifier ] +bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { +  StringRef TypeId = getTok().getIdentifier(); + +  Type = StringSwitch<COFF::COMDATType>(TypeId) +    .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) +    .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) +    .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) +    .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) +    .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) +    .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) +    .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) +    .Default((COFF::COMDATType)0); + +  if (Type == 0) +    return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); + +  Lex(); + +  return false; +} + +/// ParseDirectiveLinkOnce +///  ::= .linkonce [ identifier ] +bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { +  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; +  if (getLexer().is(AsmToken::Identifier)) +    if (parseCOMDATType(Type)) +      return true; + +  const MCSectionCOFF *Current = +      static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); + +  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) +    return Error(Loc, "cannot make section associative with .linkonce"); + +  if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) +    return Error(Loc, Twine("section '") + Current->getSectionName() + +                                                       "' is already linkonce"); + +  Current->setSelection(Type); + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return true; + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitWinCFIStartProc(Symbol, Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { +  Lex(); +  getStreamer().EmitWinCFIEndProc(Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { +  Lex(); +  getStreamer().EmitWinCFIStartChained(Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { +  Lex(); +  getStreamer().EmitWinCFIEndChained(Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { +  StringRef SymbolID; +  if (getParser().parseIdentifier(SymbolID)) +    return true; + +  if (getLexer().isNot(AsmToken::Comma)) +    return TokError("you must specify one or both of @unwind or @except"); +  Lex(); +  bool unwind = false, except = false; +  if (ParseAtUnwindOrAtExcept(unwind, except)) +    return true; +  if (getLexer().is(AsmToken::Comma)) { +    Lex(); +    if (ParseAtUnwindOrAtExcept(unwind, except)) +      return true; +  } +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); + +  Lex(); +  getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { +  Lex(); +  getStreamer().EmitWinEHHandlerData(); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { +  int64_t Size; +  if (getParser().parseAbsoluteExpression(Size)) +    return true; + +  if (getLexer().isNot(AsmToken::EndOfStatement)) +    return TokError("unexpected token in directive"); + +  Lex(); +  getStreamer().EmitWinCFIAllocStack(Size, Loc); +  return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { +  Lex(); +  getStreamer().EmitWinCFIEndProlog(Loc); +  return false; +} + +bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { +  StringRef identifier; +  if (getLexer().isNot(AsmToken::At)) +    return TokError("a handler attribute must begin with '@'"); +  SMLoc startLoc = getLexer().getLoc(); +  Lex(); +  if (getParser().parseIdentifier(identifier)) +    return Error(startLoc, "expected @unwind or @except"); +  if (identifier == "unwind") +    unwind = true; +  else if (identifier == "except") +    except = true; +  else +    return Error(startLoc, "expected @unwind or @except"); +  return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { +  return new COFFAsmParser; +} + +} // end namespace llvm  | 
