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/Twine.h" 12 #include "llvm/BinaryFormat/COFF.h" 13 #include "llvm/MC/MCContext.h" 14 #include "llvm/MC/MCDirectives.h" 15 #include "llvm/MC/MCParser/MCAsmLexer.h" 16 #include "llvm/MC/MCParser/MCAsmParserExtension.h" 17 #include "llvm/MC/MCSectionCOFF.h" 18 #include "llvm/MC/MCStreamer.h" 19 #include "llvm/Support/SMLoc.h" 20 #include "llvm/TargetParser/Triple.h" 21 #include <cassert> 22 #include <cstdint> 23 #include <limits> 24 #include <utility> 25 26 using namespace llvm; 27 28 namespace { 29 30 class COFFAsmParser : public MCAsmParserExtension { 31 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> 32 void addDirectiveHandler(StringRef Directive) { 33 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 34 this, HandleDirective<COFFAsmParser, HandlerMethod>); 35 getParser().addDirectiveHandler(Directive, Handler); 36 } 37 38 bool parseSectionSwitch(StringRef Section, unsigned Characteristics); 39 40 bool parseSectionSwitch(StringRef Section, unsigned Characteristics, 41 StringRef COMDATSymName, COFF::COMDATType Type); 42 43 bool parseSectionName(StringRef &SectionName); 44 bool parseSectionFlags(StringRef SectionName, StringRef FlagsString, 45 unsigned *Flags); 46 47 void Initialize(MCAsmParser &Parser) override { 48 // Call the base implementation. 49 MCAsmParserExtension::Initialize(Parser); 50 51 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveText>(".text"); 52 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveData>(".data"); 53 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveBSS>(".bss"); 54 addDirectiveHandler<&COFFAsmParser::parseDirectiveSection>(".section"); 55 addDirectiveHandler<&COFFAsmParser::parseDirectivePushSection>( 56 ".pushsection"); 57 addDirectiveHandler<&COFFAsmParser::parseDirectivePopSection>( 58 ".popsection"); 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::parseDirectiveSymbolAttribute>( 71 ".weak_anti_dep"); 72 addDirectiveHandler<&COFFAsmParser::parseDirectiveCGProfile>(".cg_profile"); 73 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecNum>(".secnum"); 74 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecOffset>(".secoffset"); 75 76 // Win64 EH directives. 77 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartProc>( 78 ".seh_proc"); 79 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProc>( 80 ".seh_endproc"); 81 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc>( 82 ".seh_endfunclet"); 83 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartChained>( 84 ".seh_startchained"); 85 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndChained>( 86 ".seh_endchained"); 87 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandler>( 88 ".seh_handler"); 89 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandlerData>( 90 ".seh_handlerdata"); 91 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveAllocStack>( 92 ".seh_stackalloc"); 93 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProlog>( 94 ".seh_endprologue"); 95 } 96 97 bool parseSectionDirectiveText(StringRef, SMLoc) { 98 return parseSectionSwitch(".text", COFF::IMAGE_SCN_CNT_CODE | 99 COFF::IMAGE_SCN_MEM_EXECUTE | 100 COFF::IMAGE_SCN_MEM_READ); 101 } 102 103 bool parseSectionDirectiveData(StringRef, SMLoc) { 104 return parseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 105 COFF::IMAGE_SCN_MEM_READ | 106 COFF::IMAGE_SCN_MEM_WRITE); 107 } 108 109 bool parseSectionDirectiveBSS(StringRef, SMLoc) { 110 return parseSectionSwitch(".bss", COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | 111 COFF::IMAGE_SCN_MEM_READ | 112 COFF::IMAGE_SCN_MEM_WRITE); 113 } 114 115 bool parseDirectiveSection(StringRef, SMLoc); 116 bool parseSectionArguments(StringRef, SMLoc); 117 bool parseDirectivePushSection(StringRef, SMLoc); 118 bool parseDirectivePopSection(StringRef, SMLoc); 119 bool parseDirectiveDef(StringRef, SMLoc); 120 bool parseDirectiveScl(StringRef, SMLoc); 121 bool parseDirectiveType(StringRef, SMLoc); 122 bool parseDirectiveEndef(StringRef, SMLoc); 123 bool parseDirectiveSecRel32(StringRef, SMLoc); 124 bool parseDirectiveSecIdx(StringRef, SMLoc); 125 bool parseDirectiveSafeSEH(StringRef, SMLoc); 126 bool parseDirectiveSymIdx(StringRef, SMLoc); 127 bool parseCOMDATType(COFF::COMDATType &Type); 128 bool parseDirectiveLinkOnce(StringRef, SMLoc); 129 bool parseDirectiveRVA(StringRef, SMLoc); 130 bool parseDirectiveCGProfile(StringRef, SMLoc); 131 bool parseDirectiveSecNum(StringRef, SMLoc); 132 bool parseDirectiveSecOffset(StringRef, SMLoc); 133 134 // Win64 EH directives. 135 bool parseSEHDirectiveStartProc(StringRef, SMLoc); 136 bool parseSEHDirectiveEndProc(StringRef, SMLoc); 137 bool parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc); 138 bool parseSEHDirectiveStartChained(StringRef, SMLoc); 139 bool parseSEHDirectiveEndChained(StringRef, SMLoc); 140 bool parseSEHDirectiveHandler(StringRef, SMLoc); 141 bool parseSEHDirectiveHandlerData(StringRef, SMLoc); 142 bool parseSEHDirectiveAllocStack(StringRef, SMLoc); 143 bool parseSEHDirectiveEndProlog(StringRef, SMLoc); 144 145 bool parseAtUnwindOrAtExcept(bool &unwind, bool &except); 146 bool parseDirectiveSymbolAttribute(StringRef Directive, SMLoc); 147 148 public: 149 COFFAsmParser() = default; 150 }; 151 152 } // end anonymous namespace. 153 154 bool COFFAsmParser::parseSectionFlags(StringRef SectionName, 155 StringRef FlagsString, unsigned *Flags) { 156 enum { 157 None = 0, 158 Alloc = 1 << 0, 159 Code = 1 << 1, 160 Load = 1 << 2, 161 InitData = 1 << 3, 162 Shared = 1 << 4, 163 NoLoad = 1 << 5, 164 NoRead = 1 << 6, 165 NoWrite = 1 << 7, 166 Discardable = 1 << 8, 167 Info = 1 << 9, 168 }; 169 170 bool ReadOnlyRemoved = false; 171 unsigned SecFlags = None; 172 173 for (char FlagChar : FlagsString) { 174 switch (FlagChar) { 175 case 'a': 176 // Ignored. 177 break; 178 179 case 'b': // bss section 180 SecFlags |= Alloc; 181 if (SecFlags & InitData) 182 return TokError("conflicting section flags 'b' and 'd'."); 183 SecFlags &= ~Load; 184 break; 185 186 case 'd': // data section 187 SecFlags |= InitData; 188 if (SecFlags & Alloc) 189 return TokError("conflicting section flags 'b' and 'd'."); 190 SecFlags &= ~NoWrite; 191 if ((SecFlags & NoLoad) == 0) 192 SecFlags |= Load; 193 break; 194 195 case 'n': // section is not loaded 196 SecFlags |= NoLoad; 197 SecFlags &= ~Load; 198 break; 199 200 case 'D': // discardable 201 SecFlags |= Discardable; 202 break; 203 204 case 'r': // read-only 205 ReadOnlyRemoved = false; 206 SecFlags |= NoWrite; 207 if ((SecFlags & Code) == 0) 208 SecFlags |= InitData; 209 if ((SecFlags & NoLoad) == 0) 210 SecFlags |= Load; 211 break; 212 213 case 's': // shared section 214 SecFlags |= Shared | InitData; 215 SecFlags &= ~NoWrite; 216 if ((SecFlags & NoLoad) == 0) 217 SecFlags |= Load; 218 break; 219 220 case 'w': // writable 221 SecFlags &= ~NoWrite; 222 ReadOnlyRemoved = true; 223 break; 224 225 case 'x': // executable section 226 SecFlags |= Code; 227 if ((SecFlags & NoLoad) == 0) 228 SecFlags |= Load; 229 if (!ReadOnlyRemoved) 230 SecFlags |= NoWrite; 231 break; 232 233 case 'y': // not readable 234 SecFlags |= NoRead | NoWrite; 235 break; 236 237 case 'i': // info 238 SecFlags |= Info; 239 break; 240 241 default: 242 return TokError("unknown flag"); 243 } 244 } 245 246 *Flags = 0; 247 248 if (SecFlags == None) 249 SecFlags = InitData; 250 251 if (SecFlags & Code) 252 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; 253 if (SecFlags & InitData) 254 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 255 if ((SecFlags & Alloc) && (SecFlags & Load) == 0) 256 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; 257 if (SecFlags & NoLoad) 258 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; 259 if ((SecFlags & Discardable) || 260 MCSectionCOFF::isImplicitlyDiscardable(SectionName)) 261 *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; 262 if ((SecFlags & NoRead) == 0) 263 *Flags |= COFF::IMAGE_SCN_MEM_READ; 264 if ((SecFlags & NoWrite) == 0) 265 *Flags |= COFF::IMAGE_SCN_MEM_WRITE; 266 if (SecFlags & Shared) 267 *Flags |= COFF::IMAGE_SCN_MEM_SHARED; 268 if (SecFlags & Info) 269 *Flags |= COFF::IMAGE_SCN_LNK_INFO; 270 271 return false; 272 } 273 274 /// ParseDirectiveSymbolAttribute 275 /// ::= { ".weak", ... } [ identifier ( , identifier )* ] 276 bool COFFAsmParser::parseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 277 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 278 .Case(".weak", MCSA_Weak) 279 .Case(".weak_anti_dep", MCSA_WeakAntiDep) 280 .Default(MCSA_Invalid); 281 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 282 if (getLexer().isNot(AsmToken::EndOfStatement)) { 283 while (true) { 284 StringRef Name; 285 286 if (getParser().parseIdentifier(Name)) 287 return TokError("expected identifier in directive"); 288 289 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 290 291 getStreamer().emitSymbolAttribute(Sym, Attr); 292 293 if (getLexer().is(AsmToken::EndOfStatement)) 294 break; 295 296 if (getLexer().isNot(AsmToken::Comma)) 297 return TokError("unexpected token in directive"); 298 Lex(); 299 } 300 } 301 302 Lex(); 303 return false; 304 } 305 306 bool COFFAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) { 307 return MCAsmParserExtension::parseDirectiveCGProfile(S, Loc); 308 } 309 310 bool COFFAsmParser::parseSectionSwitch(StringRef Section, 311 unsigned Characteristics) { 312 return parseSectionSwitch(Section, Characteristics, "", (COFF::COMDATType)0); 313 } 314 315 bool COFFAsmParser::parseSectionSwitch(StringRef Section, 316 unsigned Characteristics, 317 StringRef COMDATSymName, 318 COFF::COMDATType Type) { 319 if (getLexer().isNot(AsmToken::EndOfStatement)) 320 return TokError("unexpected token in section switching directive"); 321 Lex(); 322 323 getStreamer().switchSection(getContext().getCOFFSection( 324 Section, Characteristics, COMDATSymName, Type)); 325 326 return false; 327 } 328 329 bool COFFAsmParser::parseSectionName(StringRef &SectionName) { 330 if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String)) 331 return true; 332 333 SectionName = getTok().getIdentifier(); 334 Lex(); 335 return false; 336 } 337 338 bool COFFAsmParser::parseDirectiveSection(StringRef directive, SMLoc loc) { 339 return parseSectionArguments(directive, loc); 340 } 341 342 // .section name [, "flags"] [, identifier [ identifier ], identifier] 343 // .pushsection <same as above> 344 // 345 // Supported flags: 346 // a: Ignored. 347 // b: BSS section (uninitialized data) 348 // d: data section (initialized data) 349 // n: "noload" section (removed by linker) 350 // D: Discardable section 351 // r: Readable section 352 // s: Shared section 353 // w: Writable section 354 // x: Executable section 355 // y: Not-readable section (clears 'r') 356 // 357 // Subsections are not supported. 358 bool COFFAsmParser::parseSectionArguments(StringRef, SMLoc) { 359 StringRef SectionName; 360 361 if (parseSectionName(SectionName)) 362 return TokError("expected identifier in directive"); 363 364 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 365 COFF::IMAGE_SCN_MEM_READ | 366 COFF::IMAGE_SCN_MEM_WRITE; 367 368 if (getLexer().is(AsmToken::Comma)) { 369 Lex(); 370 371 if (getLexer().isNot(AsmToken::String)) 372 return TokError("expected string in directive"); 373 374 StringRef FlagsStr = getTok().getStringContents(); 375 Lex(); 376 377 if (parseSectionFlags(SectionName, FlagsStr, &Flags)) 378 return true; 379 } 380 381 COFF::COMDATType Type = (COFF::COMDATType)0; 382 StringRef COMDATSymName; 383 if (getLexer().is(AsmToken::Comma)) { 384 Type = COFF::IMAGE_COMDAT_SELECT_ANY; 385 Lex(); 386 387 Flags |= COFF::IMAGE_SCN_LNK_COMDAT; 388 389 if (!getLexer().is(AsmToken::Identifier)) 390 return TokError("expected comdat type such as 'discard' or 'largest' " 391 "after protection bits"); 392 393 if (parseCOMDATType(Type)) 394 return true; 395 396 if (getLexer().isNot(AsmToken::Comma)) 397 return TokError("expected comma in directive"); 398 Lex(); 399 400 if (getParser().parseIdentifier(COMDATSymName)) 401 return TokError("expected identifier in directive"); 402 } 403 404 if (getLexer().isNot(AsmToken::EndOfStatement)) 405 return TokError("unexpected token in directive"); 406 407 if (Flags & COFF::IMAGE_SCN_CNT_CODE) { 408 const Triple &T = getContext().getTargetTriple(); 409 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) 410 Flags |= COFF::IMAGE_SCN_MEM_16BIT; 411 } 412 parseSectionSwitch(SectionName, Flags, COMDATSymName, Type); 413 return false; 414 } 415 416 bool COFFAsmParser::parseDirectivePushSection(StringRef directive, SMLoc loc) { 417 getStreamer().pushSection(); 418 419 if (parseSectionArguments(directive, loc)) { 420 getStreamer().popSection(); 421 return true; 422 } 423 424 return false; 425 } 426 427 bool COFFAsmParser::parseDirectivePopSection(StringRef, SMLoc) { 428 if (!getStreamer().popSection()) 429 return TokError(".popsection without corresponding .pushsection"); 430 return false; 431 } 432 433 bool COFFAsmParser::parseDirectiveDef(StringRef, SMLoc) { 434 StringRef SymbolName; 435 436 if (getParser().parseIdentifier(SymbolName)) 437 return TokError("expected identifier in directive"); 438 439 MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); 440 441 getStreamer().beginCOFFSymbolDef(Sym); 442 443 Lex(); 444 return false; 445 } 446 447 bool COFFAsmParser::parseDirectiveScl(StringRef, SMLoc) { 448 int64_t SymbolStorageClass; 449 if (getParser().parseAbsoluteExpression(SymbolStorageClass)) 450 return true; 451 452 if (getLexer().isNot(AsmToken::EndOfStatement)) 453 return TokError("unexpected token in directive"); 454 455 Lex(); 456 getStreamer().emitCOFFSymbolStorageClass(SymbolStorageClass); 457 return false; 458 } 459 460 bool COFFAsmParser::parseDirectiveType(StringRef, SMLoc) { 461 int64_t Type; 462 if (getParser().parseAbsoluteExpression(Type)) 463 return true; 464 465 if (getLexer().isNot(AsmToken::EndOfStatement)) 466 return TokError("unexpected token in directive"); 467 468 Lex(); 469 getStreamer().emitCOFFSymbolType(Type); 470 return false; 471 } 472 473 bool COFFAsmParser::parseDirectiveEndef(StringRef, SMLoc) { 474 Lex(); 475 getStreamer().endCOFFSymbolDef(); 476 return false; 477 } 478 479 bool COFFAsmParser::parseDirectiveSecRel32(StringRef, SMLoc) { 480 StringRef SymbolID; 481 if (getParser().parseIdentifier(SymbolID)) 482 return TokError("expected identifier in directive"); 483 484 int64_t Offset = 0; 485 SMLoc OffsetLoc; 486 if (getLexer().is(AsmToken::Plus)) { 487 OffsetLoc = getLexer().getLoc(); 488 if (getParser().parseAbsoluteExpression(Offset)) 489 return true; 490 } 491 492 if (getLexer().isNot(AsmToken::EndOfStatement)) 493 return TokError("unexpected token in directive"); 494 495 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) 496 return Error( 497 OffsetLoc, 498 "invalid '.secrel32' directive offset, can't be less " 499 "than zero or greater than std::numeric_limits<uint32_t>::max()"); 500 501 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 502 503 Lex(); 504 getStreamer().emitCOFFSecRel32(Symbol, Offset); 505 return false; 506 } 507 508 bool COFFAsmParser::parseDirectiveRVA(StringRef, SMLoc) { 509 auto parseOp = [&]() -> bool { 510 StringRef SymbolID; 511 if (getParser().parseIdentifier(SymbolID)) 512 return TokError("expected identifier in directive"); 513 514 int64_t Offset = 0; 515 SMLoc OffsetLoc; 516 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { 517 OffsetLoc = getLexer().getLoc(); 518 if (getParser().parseAbsoluteExpression(Offset)) 519 return true; 520 } 521 522 if (Offset < std::numeric_limits<int32_t>::min() || 523 Offset > std::numeric_limits<int32_t>::max()) 524 return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " 525 "than -2147483648 or greater than " 526 "2147483647"); 527 528 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 529 530 getStreamer().emitCOFFImgRel32(Symbol, Offset); 531 return false; 532 }; 533 534 if (getParser().parseMany(parseOp)) 535 return addErrorSuffix(" in directive"); 536 return false; 537 } 538 539 bool COFFAsmParser::parseDirectiveSafeSEH(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().emitCOFFSafeSEH(Symbol); 551 return false; 552 } 553 554 bool COFFAsmParser::parseDirectiveSecIdx(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().emitCOFFSectionIndex(Symbol); 566 return false; 567 } 568 569 bool COFFAsmParser::parseDirectiveSymIdx(StringRef, SMLoc) { 570 StringRef SymbolID; 571 if (getParser().parseIdentifier(SymbolID)) 572 return TokError("expected identifier in directive"); 573 574 if (getLexer().isNot(AsmToken::EndOfStatement)) 575 return TokError("unexpected token in directive"); 576 577 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 578 579 Lex(); 580 getStreamer().emitCOFFSymbolIndex(Symbol); 581 return false; 582 } 583 584 bool COFFAsmParser::parseDirectiveSecNum(StringRef, SMLoc) { 585 StringRef SymbolID; 586 if (getParser().parseIdentifier(SymbolID)) 587 return TokError("expected identifier in directive"); 588 589 if (getLexer().isNot(AsmToken::EndOfStatement)) 590 return TokError("unexpected token in directive"); 591 592 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 593 594 Lex(); 595 getStreamer().emitCOFFSecNumber(Symbol); 596 return false; 597 } 598 599 bool COFFAsmParser::parseDirectiveSecOffset(StringRef, SMLoc) { 600 StringRef SymbolID; 601 if (getParser().parseIdentifier(SymbolID)) 602 return TokError("expected identifier in directive"); 603 604 if (getLexer().isNot(AsmToken::EndOfStatement)) 605 return TokError("unexpected token in directive"); 606 607 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 608 609 Lex(); 610 getStreamer().emitCOFFSecOffset(Symbol); 611 return false; 612 } 613 614 /// ::= [ identifier ] 615 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { 616 StringRef TypeId = getTok().getIdentifier(); 617 618 Type = StringSwitch<COFF::COMDATType>(TypeId) 619 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) 620 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) 621 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) 622 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) 623 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 624 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) 625 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) 626 .Default((COFF::COMDATType)0); 627 628 if (Type == 0) 629 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); 630 631 Lex(); 632 633 return false; 634 } 635 636 /// ParseDirectiveLinkOnce 637 /// ::= .linkonce [ identifier ] 638 bool COFFAsmParser::parseDirectiveLinkOnce(StringRef, SMLoc Loc) { 639 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; 640 if (getLexer().is(AsmToken::Identifier)) 641 if (parseCOMDATType(Type)) 642 return true; 643 644 const MCSectionCOFF *Current = 645 static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); 646 647 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 648 return Error(Loc, "cannot make section associative with .linkonce"); 649 650 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) 651 return Error(Loc, Twine("section '") + Current->getName() + 652 "' is already linkonce"); 653 654 Current->setSelection(Type); 655 656 if (getLexer().isNot(AsmToken::EndOfStatement)) 657 return TokError("unexpected token in directive"); 658 659 return false; 660 } 661 662 bool COFFAsmParser::parseSEHDirectiveStartProc(StringRef, SMLoc Loc) { 663 StringRef SymbolID; 664 if (getParser().parseIdentifier(SymbolID)) 665 return true; 666 667 if (getLexer().isNot(AsmToken::EndOfStatement)) 668 return TokError("unexpected token in directive"); 669 670 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 671 672 Lex(); 673 getStreamer().emitWinCFIStartProc(Symbol, Loc); 674 return false; 675 } 676 677 bool COFFAsmParser::parseSEHDirectiveEndProc(StringRef, SMLoc Loc) { 678 Lex(); 679 getStreamer().emitWinCFIEndProc(Loc); 680 return false; 681 } 682 683 bool COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) { 684 Lex(); 685 getStreamer().emitWinCFIFuncletOrFuncEnd(Loc); 686 return false; 687 } 688 689 bool COFFAsmParser::parseSEHDirectiveStartChained(StringRef, SMLoc Loc) { 690 Lex(); 691 getStreamer().emitWinCFIStartChained(Loc); 692 return false; 693 } 694 695 bool COFFAsmParser::parseSEHDirectiveEndChained(StringRef, SMLoc Loc) { 696 Lex(); 697 getStreamer().emitWinCFIEndChained(Loc); 698 return false; 699 } 700 701 bool COFFAsmParser::parseSEHDirectiveHandler(StringRef, SMLoc Loc) { 702 StringRef SymbolID; 703 if (getParser().parseIdentifier(SymbolID)) 704 return true; 705 706 if (getLexer().isNot(AsmToken::Comma)) 707 return TokError("you must specify one or both of @unwind or @except"); 708 Lex(); 709 bool unwind = false, except = false; 710 if (parseAtUnwindOrAtExcept(unwind, except)) 711 return true; 712 if (getLexer().is(AsmToken::Comma)) { 713 Lex(); 714 if (parseAtUnwindOrAtExcept(unwind, except)) 715 return true; 716 } 717 if (getLexer().isNot(AsmToken::EndOfStatement)) 718 return TokError("unexpected token in directive"); 719 720 MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); 721 722 Lex(); 723 getStreamer().emitWinEHHandler(handler, unwind, except, Loc); 724 return false; 725 } 726 727 bool COFFAsmParser::parseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { 728 Lex(); 729 getStreamer().emitWinEHHandlerData(); 730 return false; 731 } 732 733 bool COFFAsmParser::parseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { 734 int64_t Size; 735 if (getParser().parseAbsoluteExpression(Size)) 736 return true; 737 738 if (getLexer().isNot(AsmToken::EndOfStatement)) 739 return TokError("unexpected token in directive"); 740 741 Lex(); 742 getStreamer().emitWinCFIAllocStack(Size, Loc); 743 return false; 744 } 745 746 bool COFFAsmParser::parseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { 747 Lex(); 748 getStreamer().emitWinCFIEndProlog(Loc); 749 return false; 750 } 751 752 bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) { 753 StringRef identifier; 754 if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent)) 755 return TokError("a handler attribute must begin with '@' or '%'"); 756 SMLoc startLoc = getLexer().getLoc(); 757 Lex(); 758 if (getParser().parseIdentifier(identifier)) 759 return Error(startLoc, "expected @unwind or @except"); 760 if (identifier == "unwind") 761 unwind = true; 762 else if (identifier == "except") 763 except = true; 764 else 765 return Error(startLoc, "expected @unwind or @except"); 766 return false; 767 } 768 769 namespace llvm { 770 771 MCAsmParserExtension *createCOFFAsmParser() { 772 return new COFFAsmParser; 773 } 774 775 } // end namespace llvm 776