|  | //===- 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 anonymous 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 |