1218885Sdim//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// 2218885Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6218885Sdim// 7218885Sdim//===----------------------------------------------------------------------===// 8218885Sdim 9321369Sdim#include "llvm/ADT/StringRef.h" 10226633Sdim#include "llvm/ADT/StringSwitch.h" 11321369Sdim#include "llvm/ADT/Triple.h" 12218885Sdim#include "llvm/ADT/Twine.h" 13321369Sdim#include "llvm/BinaryFormat/COFF.h" 14218885Sdim#include "llvm/MC/MCContext.h" 15321369Sdim#include "llvm/MC/MCDirectives.h" 16276479Sdim#include "llvm/MC/MCObjectFileInfo.h" 17218885Sdim#include "llvm/MC/MCParser/MCAsmLexer.h" 18321369Sdim#include "llvm/MC/MCParser/MCAsmParserExtension.h" 19309124Sdim#include "llvm/MC/MCParser/MCTargetAsmParser.h" 20226633Sdim#include "llvm/MC/MCRegisterInfo.h" 21218885Sdim#include "llvm/MC/MCSectionCOFF.h" 22218885Sdim#include "llvm/MC/MCStreamer.h" 23321369Sdim#include "llvm/MC/SectionKind.h" 24321369Sdim#include "llvm/Support/SMLoc.h" 25321369Sdim#include <cassert> 26321369Sdim#include <cstdint> 27321369Sdim#include <limits> 28321369Sdim#include <utility> 29321369Sdim 30218885Sdimusing namespace llvm; 31218885Sdim 32218885Sdimnamespace { 33218885Sdim 34218885Sdimclass COFFAsmParser : public MCAsmParserExtension { 35249423Sdim template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> 36249423Sdim void addDirectiveHandler(StringRef Directive) { 37249423Sdim MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 38249423Sdim this, HandleDirective<COFFAsmParser, HandlerMethod>); 39249423Sdim getParser().addDirectiveHandler(Directive, Handler); 40218885Sdim } 41218885Sdim 42218885Sdim bool ParseSectionSwitch(StringRef Section, 43218885Sdim unsigned Characteristics, 44218885Sdim SectionKind Kind); 45218885Sdim 46261991Sdim bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, 47261991Sdim SectionKind Kind, StringRef COMDATSymName, 48276479Sdim COFF::COMDATType Type); 49261991Sdim 50261991Sdim bool ParseSectionName(StringRef &SectionName); 51314564Sdim bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, 52314564Sdim unsigned *Flags); 53261991Sdim 54276479Sdim void Initialize(MCAsmParser &Parser) override { 55218885Sdim // Call the base implementation. 56218885Sdim MCAsmParserExtension::Initialize(Parser); 57218885Sdim 58249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); 59249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); 60249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); 61261991Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); 62249423Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); 63249423Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); 64249423Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); 65249423Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); 66249423Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); 67341825Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); 68341825Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); 69276479Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); 70261991Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); 71341825Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); 72360784Sdim addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); 73223017Sdim 74223017Sdim // Win64 EH directives. 75249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( 76223017Sdim ".seh_proc"); 77249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( 78223017Sdim ".seh_endproc"); 79249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( 80223017Sdim ".seh_startchained"); 81249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( 82223017Sdim ".seh_endchained"); 83249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( 84223017Sdim ".seh_handler"); 85249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( 86223017Sdim ".seh_handlerdata"); 87249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( 88223017Sdim ".seh_stackalloc"); 89249423Sdim addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( 90223017Sdim ".seh_endprologue"); 91218885Sdim } 92218885Sdim 93218885Sdim bool ParseSectionDirectiveText(StringRef, SMLoc) { 94218885Sdim return ParseSectionSwitch(".text", 95218885Sdim COFF::IMAGE_SCN_CNT_CODE 96218885Sdim | COFF::IMAGE_SCN_MEM_EXECUTE 97218885Sdim | COFF::IMAGE_SCN_MEM_READ, 98218885Sdim SectionKind::getText()); 99218885Sdim } 100321369Sdim 101218885Sdim bool ParseSectionDirectiveData(StringRef, SMLoc) { 102296417Sdim return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 103296417Sdim COFF::IMAGE_SCN_MEM_READ | 104296417Sdim COFF::IMAGE_SCN_MEM_WRITE, 105296417Sdim SectionKind::getData()); 106218885Sdim } 107321369Sdim 108218885Sdim bool ParseSectionDirectiveBSS(StringRef, SMLoc) { 109218885Sdim return ParseSectionSwitch(".bss", 110218885Sdim COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA 111218885Sdim | COFF::IMAGE_SCN_MEM_READ 112218885Sdim | COFF::IMAGE_SCN_MEM_WRITE, 113218885Sdim SectionKind::getBSS()); 114218885Sdim } 115218885Sdim 116261991Sdim bool ParseDirectiveSection(StringRef, SMLoc); 117218885Sdim bool ParseDirectiveDef(StringRef, SMLoc); 118218885Sdim bool ParseDirectiveScl(StringRef, SMLoc); 119218885Sdim bool ParseDirectiveType(StringRef, SMLoc); 120218885Sdim bool ParseDirectiveEndef(StringRef, SMLoc); 121234353Sdim bool ParseDirectiveSecRel32(StringRef, SMLoc); 122276479Sdim bool ParseDirectiveSecIdx(StringRef, SMLoc); 123288943Sdim bool ParseDirectiveSafeSEH(StringRef, SMLoc); 124341825Sdim bool ParseDirectiveSymIdx(StringRef, SMLoc); 125276479Sdim bool parseCOMDATType(COFF::COMDATType &Type); 126261991Sdim bool ParseDirectiveLinkOnce(StringRef, SMLoc); 127341825Sdim bool ParseDirectiveRVA(StringRef, SMLoc); 128218885Sdim 129223017Sdim // Win64 EH directives. 130223017Sdim bool ParseSEHDirectiveStartProc(StringRef, SMLoc); 131223017Sdim bool ParseSEHDirectiveEndProc(StringRef, SMLoc); 132223017Sdim bool ParseSEHDirectiveStartChained(StringRef, SMLoc); 133223017Sdim bool ParseSEHDirectiveEndChained(StringRef, SMLoc); 134223017Sdim bool ParseSEHDirectiveHandler(StringRef, SMLoc); 135223017Sdim bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); 136223017Sdim bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); 137223017Sdim bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); 138223017Sdim 139223017Sdim bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); 140223017Sdim bool ParseSEHRegisterNumber(unsigned &RegNo); 141226633Sdim bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); 142321369Sdim 143218885Sdimpublic: 144321369Sdim COFFAsmParser() = default; 145218885Sdim}; 146218885Sdim 147360784Sdim} // end anonymous namespace. 148218885Sdim 149261991Sdimstatic SectionKind computeSectionKind(unsigned Flags) { 150261991Sdim if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) 151261991Sdim return SectionKind::getText(); 152261991Sdim if (Flags & COFF::IMAGE_SCN_MEM_READ && 153261991Sdim (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) 154261991Sdim return SectionKind::getReadOnly(); 155296417Sdim return SectionKind::getData(); 156261991Sdim} 157261991Sdim 158314564Sdimbool COFFAsmParser::ParseSectionFlags(StringRef SectionName, 159314564Sdim StringRef FlagsString, unsigned *Flags) { 160261991Sdim enum { 161314564Sdim None = 0, 162314564Sdim Alloc = 1 << 0, 163314564Sdim Code = 1 << 1, 164314564Sdim Load = 1 << 2, 165314564Sdim InitData = 1 << 3, 166314564Sdim Shared = 1 << 4, 167314564Sdim NoLoad = 1 << 5, 168314564Sdim NoRead = 1 << 6, 169314564Sdim NoWrite = 1 << 7, 170314564Sdim Discardable = 1 << 8, 171261991Sdim }; 172261991Sdim 173261991Sdim bool ReadOnlyRemoved = false; 174261991Sdim unsigned SecFlags = None; 175261991Sdim 176276479Sdim for (char FlagChar : FlagsString) { 177276479Sdim switch (FlagChar) { 178261991Sdim case 'a': 179261991Sdim // Ignored. 180261991Sdim break; 181261991Sdim 182261991Sdim case 'b': // bss section 183261991Sdim SecFlags |= Alloc; 184261991Sdim if (SecFlags & InitData) 185261991Sdim return TokError("conflicting section flags 'b' and 'd'."); 186261991Sdim SecFlags &= ~Load; 187261991Sdim break; 188261991Sdim 189261991Sdim case 'd': // data section 190261991Sdim SecFlags |= InitData; 191261991Sdim if (SecFlags & Alloc) 192261991Sdim return TokError("conflicting section flags 'b' and 'd'."); 193261991Sdim SecFlags &= ~NoWrite; 194261991Sdim if ((SecFlags & NoLoad) == 0) 195261991Sdim SecFlags |= Load; 196261991Sdim break; 197261991Sdim 198261991Sdim case 'n': // section is not loaded 199261991Sdim SecFlags |= NoLoad; 200261991Sdim SecFlags &= ~Load; 201261991Sdim break; 202261991Sdim 203314564Sdim case 'D': // discardable 204314564Sdim SecFlags |= Discardable; 205314564Sdim break; 206314564Sdim 207261991Sdim case 'r': // read-only 208261991Sdim ReadOnlyRemoved = false; 209261991Sdim SecFlags |= NoWrite; 210261991Sdim if ((SecFlags & Code) == 0) 211261991Sdim SecFlags |= InitData; 212261991Sdim if ((SecFlags & NoLoad) == 0) 213261991Sdim SecFlags |= Load; 214261991Sdim break; 215261991Sdim 216261991Sdim case 's': // shared section 217261991Sdim SecFlags |= Shared | InitData; 218261991Sdim SecFlags &= ~NoWrite; 219261991Sdim if ((SecFlags & NoLoad) == 0) 220261991Sdim SecFlags |= Load; 221261991Sdim break; 222261991Sdim 223261991Sdim case 'w': // writable 224261991Sdim SecFlags &= ~NoWrite; 225261991Sdim ReadOnlyRemoved = true; 226261991Sdim break; 227261991Sdim 228261991Sdim case 'x': // executable section 229261991Sdim SecFlags |= Code; 230261991Sdim if ((SecFlags & NoLoad) == 0) 231261991Sdim SecFlags |= Load; 232261991Sdim if (!ReadOnlyRemoved) 233261991Sdim SecFlags |= NoWrite; 234261991Sdim break; 235261991Sdim 236261991Sdim case 'y': // not readable 237261991Sdim SecFlags |= NoRead | NoWrite; 238261991Sdim break; 239261991Sdim 240261991Sdim default: 241261991Sdim return TokError("unknown flag"); 242261991Sdim } 243261991Sdim } 244261991Sdim 245261991Sdim *Flags = 0; 246261991Sdim 247261991Sdim if (SecFlags == None) 248261991Sdim SecFlags = InitData; 249261991Sdim 250261991Sdim if (SecFlags & Code) 251261991Sdim *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; 252261991Sdim if (SecFlags & InitData) 253261991Sdim *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 254261991Sdim if ((SecFlags & Alloc) && (SecFlags & Load) == 0) 255261991Sdim *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; 256261991Sdim if (SecFlags & NoLoad) 257261991Sdim *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; 258314564Sdim if ((SecFlags & Discardable) || 259314564Sdim MCSectionCOFF::isImplicitlyDiscardable(SectionName)) 260314564Sdim *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; 261261991Sdim if ((SecFlags & NoRead) == 0) 262261991Sdim *Flags |= COFF::IMAGE_SCN_MEM_READ; 263261991Sdim if ((SecFlags & NoWrite) == 0) 264261991Sdim *Flags |= COFF::IMAGE_SCN_MEM_WRITE; 265261991Sdim if (SecFlags & Shared) 266261991Sdim *Flags |= COFF::IMAGE_SCN_MEM_SHARED; 267261991Sdim 268261991Sdim return false; 269261991Sdim} 270261991Sdim 271226633Sdim/// ParseDirectiveSymbolAttribute 272226633Sdim/// ::= { ".weak", ... } [ identifier ( , identifier )* ] 273226633Sdimbool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 274226633Sdim MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 275226633Sdim .Case(".weak", MCSA_Weak) 276226633Sdim .Default(MCSA_Invalid); 277226633Sdim assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 278226633Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) { 279321369Sdim while (true) { 280226633Sdim StringRef Name; 281226633Sdim 282249423Sdim if (getParser().parseIdentifier(Name)) 283226633Sdim return TokError("expected identifier in directive"); 284226633Sdim 285288943Sdim MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 286226633Sdim 287226633Sdim getStreamer().EmitSymbolAttribute(Sym, Attr); 288226633Sdim 289226633Sdim if (getLexer().is(AsmToken::EndOfStatement)) 290226633Sdim break; 291226633Sdim 292226633Sdim if (getLexer().isNot(AsmToken::Comma)) 293226633Sdim return TokError("unexpected token in directive"); 294226633Sdim Lex(); 295226633Sdim } 296226633Sdim } 297226633Sdim 298226633Sdim Lex(); 299226633Sdim return false; 300226633Sdim} 301226633Sdim 302218885Sdimbool COFFAsmParser::ParseSectionSwitch(StringRef Section, 303218885Sdim unsigned Characteristics, 304218885Sdim SectionKind Kind) { 305276479Sdim return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0); 306261991Sdim} 307261991Sdim 308261991Sdimbool COFFAsmParser::ParseSectionSwitch(StringRef Section, 309261991Sdim unsigned Characteristics, 310261991Sdim SectionKind Kind, 311261991Sdim StringRef COMDATSymName, 312276479Sdim COFF::COMDATType Type) { 313218885Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 314218885Sdim return TokError("unexpected token in section switching directive"); 315218885Sdim Lex(); 316218885Sdim 317218885Sdim getStreamer().SwitchSection(getContext().getCOFFSection( 318276479Sdim Section, Characteristics, Kind, COMDATSymName, Type)); 319218885Sdim 320218885Sdim return false; 321218885Sdim} 322218885Sdim 323261991Sdimbool COFFAsmParser::ParseSectionName(StringRef &SectionName) { 324261991Sdim if (!getLexer().is(AsmToken::Identifier)) 325261991Sdim return true; 326261991Sdim 327261991Sdim SectionName = getTok().getIdentifier(); 328261991Sdim Lex(); 329261991Sdim return false; 330261991Sdim} 331261991Sdim 332261991Sdim// .section name [, "flags"] [, identifier [ identifier ], identifier] 333261991Sdim// 334261991Sdim// Supported flags: 335261991Sdim// a: Ignored. 336261991Sdim// b: BSS section (uninitialized data) 337261991Sdim// d: data section (initialized data) 338314564Sdim// n: "noload" section (removed by linker) 339314564Sdim// D: Discardable section 340261991Sdim// r: Readable section 341261991Sdim// s: Shared section 342261991Sdim// w: Writable section 343261991Sdim// x: Executable section 344261991Sdim// y: Not-readable section (clears 'r') 345261991Sdim// 346261991Sdim// Subsections are not supported. 347261991Sdimbool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { 348261991Sdim StringRef SectionName; 349261991Sdim 350261991Sdim if (ParseSectionName(SectionName)) 351261991Sdim return TokError("expected identifier in directive"); 352261991Sdim 353261991Sdim unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 354261991Sdim COFF::IMAGE_SCN_MEM_READ | 355261991Sdim COFF::IMAGE_SCN_MEM_WRITE; 356261991Sdim 357261991Sdim if (getLexer().is(AsmToken::Comma)) { 358261991Sdim Lex(); 359261991Sdim 360261991Sdim if (getLexer().isNot(AsmToken::String)) 361261991Sdim return TokError("expected string in directive"); 362261991Sdim 363261991Sdim StringRef FlagsStr = getTok().getStringContents(); 364261991Sdim Lex(); 365261991Sdim 366314564Sdim if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) 367261991Sdim return true; 368261991Sdim } 369261991Sdim 370276479Sdim COFF::COMDATType Type = (COFF::COMDATType)0; 371261991Sdim StringRef COMDATSymName; 372261991Sdim if (getLexer().is(AsmToken::Comma)) { 373288943Sdim Type = COFF::IMAGE_COMDAT_SELECT_ANY; 374261991Sdim Lex(); 375261991Sdim 376261991Sdim Flags |= COFF::IMAGE_SCN_LNK_COMDAT; 377261991Sdim 378280031Sdim if (!getLexer().is(AsmToken::Identifier)) 379280031Sdim return TokError("expected comdat type such as 'discard' or 'largest' " 380280031Sdim "after protection bits"); 381280031Sdim 382276479Sdim if (parseCOMDATType(Type)) 383261991Sdim return true; 384261991Sdim 385261991Sdim if (getLexer().isNot(AsmToken::Comma)) 386261991Sdim return TokError("expected comma in directive"); 387261991Sdim Lex(); 388261991Sdim 389261991Sdim if (getParser().parseIdentifier(COMDATSymName)) 390261991Sdim return TokError("expected identifier in directive"); 391261991Sdim } 392261991Sdim 393261991Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 394261991Sdim return TokError("unexpected token in directive"); 395261991Sdim 396261991Sdim SectionKind Kind = computeSectionKind(Flags); 397276479Sdim if (Kind.isText()) { 398276479Sdim const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); 399276479Sdim if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) 400276479Sdim Flags |= COFF::IMAGE_SCN_MEM_16BIT; 401276479Sdim } 402276479Sdim ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type); 403261991Sdim return false; 404261991Sdim} 405261991Sdim 406218885Sdimbool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { 407218885Sdim StringRef SymbolName; 408218885Sdim 409249423Sdim if (getParser().parseIdentifier(SymbolName)) 410218885Sdim return TokError("expected identifier in directive"); 411218885Sdim 412288943Sdim MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); 413218885Sdim 414218885Sdim getStreamer().BeginCOFFSymbolDef(Sym); 415218885Sdim 416218885Sdim Lex(); 417218885Sdim return false; 418218885Sdim} 419218885Sdim 420218885Sdimbool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { 421218885Sdim int64_t SymbolStorageClass; 422249423Sdim if (getParser().parseAbsoluteExpression(SymbolStorageClass)) 423218885Sdim return true; 424218885Sdim 425218885Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 426218885Sdim return TokError("unexpected token in directive"); 427218885Sdim 428218885Sdim Lex(); 429218885Sdim getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); 430218885Sdim return false; 431218885Sdim} 432218885Sdim 433218885Sdimbool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { 434218885Sdim int64_t Type; 435249423Sdim if (getParser().parseAbsoluteExpression(Type)) 436218885Sdim return true; 437218885Sdim 438218885Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 439218885Sdim return TokError("unexpected token in directive"); 440218885Sdim 441218885Sdim Lex(); 442218885Sdim getStreamer().EmitCOFFSymbolType(Type); 443218885Sdim return false; 444218885Sdim} 445218885Sdim 446218885Sdimbool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { 447218885Sdim Lex(); 448218885Sdim getStreamer().EndCOFFSymbolDef(); 449218885Sdim return false; 450218885Sdim} 451218885Sdim 452234353Sdimbool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { 453234353Sdim StringRef SymbolID; 454249423Sdim if (getParser().parseIdentifier(SymbolID)) 455276479Sdim return TokError("expected identifier in directive"); 456234353Sdim 457314564Sdim int64_t Offset = 0; 458314564Sdim SMLoc OffsetLoc; 459314564Sdim if (getLexer().is(AsmToken::Plus)) { 460314564Sdim OffsetLoc = getLexer().getLoc(); 461314564Sdim if (getParser().parseAbsoluteExpression(Offset)) 462314564Sdim return true; 463314564Sdim } 464314564Sdim 465234353Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 466234353Sdim return TokError("unexpected token in directive"); 467234353Sdim 468321369Sdim if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) 469321369Sdim return Error( 470321369Sdim OffsetLoc, 471321369Sdim "invalid '.secrel32' directive offset, can't be less " 472321369Sdim "than zero or greater than std::numeric_limits<uint32_t>::max()"); 473314564Sdim 474288943Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 475234353Sdim 476234353Sdim Lex(); 477314564Sdim getStreamer().EmitCOFFSecRel32(Symbol, Offset); 478234353Sdim return false; 479234353Sdim} 480234353Sdim 481341825Sdimbool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { 482341825Sdim auto parseOp = [&]() -> bool { 483341825Sdim StringRef SymbolID; 484341825Sdim if (getParser().parseIdentifier(SymbolID)) 485341825Sdim return TokError("expected identifier in directive"); 486341825Sdim 487341825Sdim int64_t Offset = 0; 488341825Sdim SMLoc OffsetLoc; 489341825Sdim if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { 490341825Sdim OffsetLoc = getLexer().getLoc(); 491341825Sdim if (getParser().parseAbsoluteExpression(Offset)) 492341825Sdim return true; 493341825Sdim } 494341825Sdim 495341825Sdim if (Offset < std::numeric_limits<int32_t>::min() || 496341825Sdim Offset > std::numeric_limits<int32_t>::max()) 497341825Sdim return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " 498341825Sdim "than -2147483648 or greater than " 499341825Sdim "2147483647"); 500341825Sdim 501341825Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 502341825Sdim 503341825Sdim getStreamer().EmitCOFFImgRel32(Symbol, Offset); 504341825Sdim return false; 505341825Sdim }; 506341825Sdim 507341825Sdim if (getParser().parseMany(parseOp)) 508341825Sdim return addErrorSuffix(" in directive"); 509341825Sdim return false; 510341825Sdim} 511341825Sdim 512288943Sdimbool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { 513288943Sdim StringRef SymbolID; 514288943Sdim if (getParser().parseIdentifier(SymbolID)) 515288943Sdim return TokError("expected identifier in directive"); 516288943Sdim 517288943Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 518288943Sdim return TokError("unexpected token in directive"); 519288943Sdim 520288943Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 521288943Sdim 522288943Sdim Lex(); 523288943Sdim getStreamer().EmitCOFFSafeSEH(Symbol); 524288943Sdim return false; 525288943Sdim} 526288943Sdim 527276479Sdimbool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { 528276479Sdim StringRef SymbolID; 529276479Sdim if (getParser().parseIdentifier(SymbolID)) 530276479Sdim return TokError("expected identifier in directive"); 531276479Sdim 532276479Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 533276479Sdim return TokError("unexpected token in directive"); 534276479Sdim 535288943Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 536276479Sdim 537276479Sdim Lex(); 538276479Sdim getStreamer().EmitCOFFSectionIndex(Symbol); 539276479Sdim return false; 540276479Sdim} 541276479Sdim 542341825Sdimbool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { 543341825Sdim StringRef SymbolID; 544341825Sdim if (getParser().parseIdentifier(SymbolID)) 545341825Sdim return TokError("expected identifier in directive"); 546341825Sdim 547341825Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 548341825Sdim return TokError("unexpected token in directive"); 549341825Sdim 550341825Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 551341825Sdim 552341825Sdim Lex(); 553341825Sdim getStreamer().EmitCOFFSymbolIndex(Symbol); 554341825Sdim return false; 555341825Sdim} 556341825Sdim 557276479Sdim/// ::= [ identifier ] 558276479Sdimbool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { 559261991Sdim StringRef TypeId = getTok().getIdentifier(); 560261991Sdim 561261991Sdim Type = StringSwitch<COFF::COMDATType>(TypeId) 562261991Sdim .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) 563261991Sdim .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) 564261991Sdim .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) 565261991Sdim .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) 566261991Sdim .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 567261991Sdim .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) 568261991Sdim .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) 569261991Sdim .Default((COFF::COMDATType)0); 570261991Sdim 571261991Sdim if (Type == 0) 572261991Sdim return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); 573261991Sdim 574261991Sdim Lex(); 575261991Sdim 576261991Sdim return false; 577261991Sdim} 578261991Sdim 579261991Sdim/// ParseDirectiveLinkOnce 580276479Sdim/// ::= .linkonce [ identifier ] 581261991Sdimbool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { 582261991Sdim COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; 583261991Sdim if (getLexer().is(AsmToken::Identifier)) 584276479Sdim if (parseCOMDATType(Type)) 585261991Sdim return true; 586261991Sdim 587314564Sdim const MCSectionCOFF *Current = 588314564Sdim static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); 589261991Sdim 590276479Sdim if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 591276479Sdim return Error(Loc, "cannot make section associative with .linkonce"); 592261991Sdim 593261991Sdim if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) 594261991Sdim return Error(Loc, Twine("section '") + Current->getSectionName() + 595261991Sdim "' is already linkonce"); 596261991Sdim 597276479Sdim Current->setSelection(Type); 598261991Sdim 599261991Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 600261991Sdim return TokError("unexpected token in directive"); 601261991Sdim 602261991Sdim return false; 603261991Sdim} 604261991Sdim 605327952Sdimbool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { 606223017Sdim StringRef SymbolID; 607249423Sdim if (getParser().parseIdentifier(SymbolID)) 608223017Sdim return true; 609223017Sdim 610223017Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 611223017Sdim return TokError("unexpected token in directive"); 612223017Sdim 613288943Sdim MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 614223017Sdim 615223017Sdim Lex(); 616327952Sdim getStreamer().EmitWinCFIStartProc(Symbol, Loc); 617223017Sdim return false; 618223017Sdim} 619223017Sdim 620327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { 621223017Sdim Lex(); 622327952Sdim getStreamer().EmitWinCFIEndProc(Loc); 623223017Sdim return false; 624223017Sdim} 625223017Sdim 626327952Sdimbool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { 627223017Sdim Lex(); 628327952Sdim getStreamer().EmitWinCFIStartChained(Loc); 629223017Sdim return false; 630223017Sdim} 631223017Sdim 632327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { 633223017Sdim Lex(); 634327952Sdim getStreamer().EmitWinCFIEndChained(Loc); 635223017Sdim return false; 636223017Sdim} 637223017Sdim 638327952Sdimbool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { 639223017Sdim StringRef SymbolID; 640249423Sdim if (getParser().parseIdentifier(SymbolID)) 641223017Sdim return true; 642223017Sdim 643223017Sdim if (getLexer().isNot(AsmToken::Comma)) 644223017Sdim return TokError("you must specify one or both of @unwind or @except"); 645223017Sdim Lex(); 646223017Sdim bool unwind = false, except = false; 647223017Sdim if (ParseAtUnwindOrAtExcept(unwind, except)) 648223017Sdim return true; 649223017Sdim if (getLexer().is(AsmToken::Comma)) { 650223017Sdim Lex(); 651223017Sdim if (ParseAtUnwindOrAtExcept(unwind, except)) 652223017Sdim return true; 653223017Sdim } 654223017Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 655223017Sdim return TokError("unexpected token in directive"); 656223017Sdim 657288943Sdim MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); 658223017Sdim 659223017Sdim Lex(); 660327952Sdim getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); 661223017Sdim return false; 662223017Sdim} 663223017Sdim 664327952Sdimbool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { 665223017Sdim Lex(); 666276479Sdim getStreamer().EmitWinEHHandlerData(); 667223017Sdim return false; 668223017Sdim} 669223017Sdim 670327952Sdimbool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { 671223017Sdim int64_t Size; 672249423Sdim if (getParser().parseAbsoluteExpression(Size)) 673223017Sdim return true; 674223017Sdim 675223017Sdim if (getLexer().isNot(AsmToken::EndOfStatement)) 676223017Sdim return TokError("unexpected token in directive"); 677223017Sdim 678223017Sdim Lex(); 679327952Sdim getStreamer().EmitWinCFIAllocStack(Size, Loc); 680223017Sdim return false; 681223017Sdim} 682223017Sdim 683327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { 684223017Sdim Lex(); 685327952Sdim getStreamer().EmitWinCFIEndProlog(Loc); 686223017Sdim return false; 687223017Sdim} 688223017Sdim 689223017Sdimbool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { 690223017Sdim StringRef identifier; 691223017Sdim if (getLexer().isNot(AsmToken::At)) 692223017Sdim return TokError("a handler attribute must begin with '@'"); 693223017Sdim SMLoc startLoc = getLexer().getLoc(); 694223017Sdim Lex(); 695249423Sdim if (getParser().parseIdentifier(identifier)) 696223017Sdim return Error(startLoc, "expected @unwind or @except"); 697223017Sdim if (identifier == "unwind") 698223017Sdim unwind = true; 699223017Sdim else if (identifier == "except") 700223017Sdim except = true; 701223017Sdim else 702223017Sdim return Error(startLoc, "expected @unwind or @except"); 703223017Sdim return false; 704223017Sdim} 705223017Sdim 706218885Sdimnamespace llvm { 707218885Sdim 708218885SdimMCAsmParserExtension *createCOFFAsmParser() { 709218885Sdim return new COFFAsmParser; 710218885Sdim} 711218885Sdim 712321369Sdim} // end namespace llvm 713