1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/StringRef.h" 10 #include "llvm/ADT/StringSwitch.h" 11 #include "llvm/ADT/Triple.h" 12 #include "llvm/ADT/Twine.h" 13 #include "llvm/BinaryFormat/COFF.h" 14 #include "llvm/MC/MCContext.h" 15 #include "llvm/MC/MCDirectives.h" 16 #include "llvm/MC/MCObjectFileInfo.h" 17 #include "llvm/MC/MCParser/MCAsmLexer.h" 18 #include "llvm/MC/MCParser/MCAsmParserExtension.h" 19 #include "llvm/MC/MCParser/MCTargetAsmParser.h" 20 #include "llvm/MC/MCRegisterInfo.h" 21 #include "llvm/MC/MCSectionCOFF.h" 22 #include "llvm/MC/MCStreamer.h" 23 #include "llvm/MC/SectionKind.h" 24 #include "llvm/Support/SMLoc.h" 25 #include <cassert> 26 #include <cstdint> 27 #include <limits> 28 #include <utility> 29 30 using namespace llvm; 31 32 namespace { 33 34 class COFFAsmParser : public MCAsmParserExtension { 35 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> 36 void addDirectiveHandler(StringRef Directive) { 37 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 38 this, HandleDirective<COFFAsmParser, HandlerMethod>); 39 getParser().addDirectiveHandler(Directive, Handler); 40 } 41 42 bool ParseSectionSwitch(StringRef Section, 43 unsigned Characteristics, 44 SectionKind Kind); 45 46 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, 47 SectionKind Kind, StringRef COMDATSymName, 48 COFF::COMDATType Type); 49 50 bool ParseSectionName(StringRef &SectionName); 51 bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString, 52 unsigned *Flags); 53 54 void Initialize(MCAsmParser &Parser) override { 55 // Call the base implementation. 56 MCAsmParserExtension::Initialize(Parser); 57 58 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); 59 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); 60 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); 61 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); 62 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); 63 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); 64 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); 65 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); 66 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); 67 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx"); 68 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh"); 69 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx"); 70 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); 71 addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva"); 72 73 // Win64 EH directives. 74 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( 75 ".seh_proc"); 76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( 77 ".seh_endproc"); 78 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( 79 ".seh_startchained"); 80 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( 81 ".seh_endchained"); 82 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( 83 ".seh_handler"); 84 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( 85 ".seh_handlerdata"); 86 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>( 87 ".seh_pushreg"); 88 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>( 89 ".seh_setframe"); 90 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( 91 ".seh_stackalloc"); 92 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>( 93 ".seh_savereg"); 94 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>( 95 ".seh_savexmm"); 96 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>( 97 ".seh_pushframe"); 98 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( 99 ".seh_endprologue"); 100 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); 101 } 102 103 bool ParseSectionDirectiveText(StringRef, SMLoc) { 104 return ParseSectionSwitch(".text", 105 COFF::IMAGE_SCN_CNT_CODE 106 | COFF::IMAGE_SCN_MEM_EXECUTE 107 | COFF::IMAGE_SCN_MEM_READ, 108 SectionKind::getText()); 109 } 110 111 bool ParseSectionDirectiveData(StringRef, SMLoc) { 112 return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 113 COFF::IMAGE_SCN_MEM_READ | 114 COFF::IMAGE_SCN_MEM_WRITE, 115 SectionKind::getData()); 116 } 117 118 bool ParseSectionDirectiveBSS(StringRef, SMLoc) { 119 return ParseSectionSwitch(".bss", 120 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA 121 | COFF::IMAGE_SCN_MEM_READ 122 | COFF::IMAGE_SCN_MEM_WRITE, 123 SectionKind::getBSS()); 124 } 125 126 bool ParseDirectiveSection(StringRef, SMLoc); 127 bool ParseDirectiveDef(StringRef, SMLoc); 128 bool ParseDirectiveScl(StringRef, SMLoc); 129 bool ParseDirectiveType(StringRef, SMLoc); 130 bool ParseDirectiveEndef(StringRef, SMLoc); 131 bool ParseDirectiveSecRel32(StringRef, SMLoc); 132 bool ParseDirectiveSecIdx(StringRef, SMLoc); 133 bool ParseDirectiveSafeSEH(StringRef, SMLoc); 134 bool ParseDirectiveSymIdx(StringRef, SMLoc); 135 bool parseCOMDATType(COFF::COMDATType &Type); 136 bool ParseDirectiveLinkOnce(StringRef, SMLoc); 137 bool ParseDirectiveRVA(StringRef, SMLoc); 138 139 // Win64 EH directives. 140 bool ParseSEHDirectiveStartProc(StringRef, SMLoc); 141 bool ParseSEHDirectiveEndProc(StringRef, SMLoc); 142 bool ParseSEHDirectiveStartChained(StringRef, SMLoc); 143 bool ParseSEHDirectiveEndChained(StringRef, SMLoc); 144 bool ParseSEHDirectiveHandler(StringRef, SMLoc); 145 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); 146 bool ParseSEHDirectivePushReg(StringRef, SMLoc); 147 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc); 148 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); 149 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc); 150 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc); 151 bool ParseSEHDirectivePushFrame(StringRef, SMLoc); 152 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); 153 154 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); 155 bool ParseSEHRegisterNumber(unsigned &RegNo); 156 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); 157 158 public: 159 COFFAsmParser() = default; 160 }; 161 162 } // end annonomous namespace. 163 164 static SectionKind computeSectionKind(unsigned Flags) { 165 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) 166 return SectionKind::getText(); 167 if (Flags & COFF::IMAGE_SCN_MEM_READ && 168 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) 169 return SectionKind::getReadOnly(); 170 return SectionKind::getData(); 171 } 172 173 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName, 174 StringRef FlagsString, unsigned *Flags) { 175 enum { 176 None = 0, 177 Alloc = 1 << 0, 178 Code = 1 << 1, 179 Load = 1 << 2, 180 InitData = 1 << 3, 181 Shared = 1 << 4, 182 NoLoad = 1 << 5, 183 NoRead = 1 << 6, 184 NoWrite = 1 << 7, 185 Discardable = 1 << 8, 186 }; 187 188 bool ReadOnlyRemoved = false; 189 unsigned SecFlags = None; 190 191 for (char FlagChar : FlagsString) { 192 switch (FlagChar) { 193 case 'a': 194 // Ignored. 195 break; 196 197 case 'b': // bss section 198 SecFlags |= Alloc; 199 if (SecFlags & InitData) 200 return TokError("conflicting section flags 'b' and 'd'."); 201 SecFlags &= ~Load; 202 break; 203 204 case 'd': // data section 205 SecFlags |= InitData; 206 if (SecFlags & Alloc) 207 return TokError("conflicting section flags 'b' and 'd'."); 208 SecFlags &= ~NoWrite; 209 if ((SecFlags & NoLoad) == 0) 210 SecFlags |= Load; 211 break; 212 213 case 'n': // section is not loaded 214 SecFlags |= NoLoad; 215 SecFlags &= ~Load; 216 break; 217 218 case 'D': // discardable 219 SecFlags |= Discardable; 220 break; 221 222 case 'r': // read-only 223 ReadOnlyRemoved = false; 224 SecFlags |= NoWrite; 225 if ((SecFlags & Code) == 0) 226 SecFlags |= InitData; 227 if ((SecFlags & NoLoad) == 0) 228 SecFlags |= Load; 229 break; 230 231 case 's': // shared section 232 SecFlags |= Shared | InitData; 233 SecFlags &= ~NoWrite; 234 if ((SecFlags & NoLoad) == 0) 235 SecFlags |= Load; 236 break; 237 238 case 'w': // writable 239 SecFlags &= ~NoWrite; 240 ReadOnlyRemoved = true; 241 break; 242 243 case 'x': // executable section 244 SecFlags |= Code; 245 if ((SecFlags & NoLoad) == 0) 246 SecFlags |= Load; 247 if (!ReadOnlyRemoved) 248 SecFlags |= NoWrite; 249 break; 250 251 case 'y': // not readable 252 SecFlags |= NoRead | NoWrite; 253 break; 254 255 default: 256 return TokError("unknown flag"); 257 } 258 } 259 260 *Flags = 0; 261 262 if (SecFlags == None) 263 SecFlags = InitData; 264 265 if (SecFlags & Code) 266 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; 267 if (SecFlags & InitData) 268 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 269 if ((SecFlags & Alloc) && (SecFlags & Load) == 0) 270 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; 271 if (SecFlags & NoLoad) 272 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; 273 if ((SecFlags & Discardable) || 274 MCSectionCOFF::isImplicitlyDiscardable(SectionName)) 275 *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; 276 if ((SecFlags & NoRead) == 0) 277 *Flags |= COFF::IMAGE_SCN_MEM_READ; 278 if ((SecFlags & NoWrite) == 0) 279 *Flags |= COFF::IMAGE_SCN_MEM_WRITE; 280 if (SecFlags & Shared) 281 *Flags |= COFF::IMAGE_SCN_MEM_SHARED; 282 283 return false; 284 } 285 286 /// ParseDirectiveSymbolAttribute 287 /// ::= { ".weak", ... } [ identifier ( , identifier )* ] 288 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 289 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 290 .Case(".weak", MCSA_Weak) 291 .Default(MCSA_Invalid); 292 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 293 if (getLexer().isNot(AsmToken::EndOfStatement)) { 294 while (true) { 295 StringRef Name; 296 297 if (getParser().parseIdentifier(Name)) 298 return TokError("expected identifier in directive"); 299 300 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 301 302 getStreamer().EmitSymbolAttribute(Sym, Attr); 303 304 if (getLexer().is(AsmToken::EndOfStatement)) 305 break; 306 307 if (getLexer().isNot(AsmToken::Comma)) 308 return TokError("unexpected token in directive"); 309 Lex(); 310 } 311 } 312 313 Lex(); 314 return false; 315 } 316 317 bool COFFAsmParser::ParseSectionSwitch(StringRef Section, 318 unsigned Characteristics, 319 SectionKind Kind) { 320 return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0); 321 } 322 323 bool COFFAsmParser::ParseSectionSwitch(StringRef Section, 324 unsigned Characteristics, 325 SectionKind Kind, 326 StringRef COMDATSymName, 327 COFF::COMDATType Type) { 328 if (getLexer().isNot(AsmToken::EndOfStatement)) 329 return TokError("unexpected token in section switching directive"); 330 Lex(); 331 332 getStreamer().SwitchSection(getContext().getCOFFSection( 333 Section, Characteristics, Kind, COMDATSymName, Type)); 334 335 return false; 336 } 337 338 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { 339 if (!getLexer().is(AsmToken::Identifier)) 340 return true; 341 342 SectionName = getTok().getIdentifier(); 343 Lex(); 344 return false; 345 } 346 347 // .section name [, "flags"] [, identifier [ identifier ], identifier] 348 // 349 // Supported flags: 350 // a: Ignored. 351 // b: BSS section (uninitialized data) 352 // d: data section (initialized data) 353 // n: "noload" section (removed by linker) 354 // D: Discardable section 355 // r: Readable section 356 // s: Shared section 357 // w: Writable section 358 // x: Executable section 359 // y: Not-readable section (clears 'r') 360 // 361 // Subsections are not supported. 362 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { 363 StringRef SectionName; 364 365 if (ParseSectionName(SectionName)) 366 return TokError("expected identifier in directive"); 367 368 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | 369 COFF::IMAGE_SCN_MEM_READ | 370 COFF::IMAGE_SCN_MEM_WRITE; 371 372 if (getLexer().is(AsmToken::Comma)) { 373 Lex(); 374 375 if (getLexer().isNot(AsmToken::String)) 376 return TokError("expected string in directive"); 377 378 StringRef FlagsStr = getTok().getStringContents(); 379 Lex(); 380 381 if (ParseSectionFlags(SectionName, FlagsStr, &Flags)) 382 return true; 383 } 384 385 COFF::COMDATType Type = (COFF::COMDATType)0; 386 StringRef COMDATSymName; 387 if (getLexer().is(AsmToken::Comma)) { 388 Type = COFF::IMAGE_COMDAT_SELECT_ANY; 389 Lex(); 390 391 Flags |= COFF::IMAGE_SCN_LNK_COMDAT; 392 393 if (!getLexer().is(AsmToken::Identifier)) 394 return TokError("expected comdat type such as 'discard' or 'largest' " 395 "after protection bits"); 396 397 if (parseCOMDATType(Type)) 398 return true; 399 400 if (getLexer().isNot(AsmToken::Comma)) 401 return TokError("expected comma in directive"); 402 Lex(); 403 404 if (getParser().parseIdentifier(COMDATSymName)) 405 return TokError("expected identifier in directive"); 406 } 407 408 if (getLexer().isNot(AsmToken::EndOfStatement)) 409 return TokError("unexpected token in directive"); 410 411 SectionKind Kind = computeSectionKind(Flags); 412 if (Kind.isText()) { 413 const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); 414 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) 415 Flags |= COFF::IMAGE_SCN_MEM_16BIT; 416 } 417 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type); 418 return false; 419 } 420 421 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { 422 StringRef SymbolName; 423 424 if (getParser().parseIdentifier(SymbolName)) 425 return TokError("expected identifier in directive"); 426 427 MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName); 428 429 getStreamer().BeginCOFFSymbolDef(Sym); 430 431 Lex(); 432 return false; 433 } 434 435 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { 436 int64_t SymbolStorageClass; 437 if (getParser().parseAbsoluteExpression(SymbolStorageClass)) 438 return true; 439 440 if (getLexer().isNot(AsmToken::EndOfStatement)) 441 return TokError("unexpected token in directive"); 442 443 Lex(); 444 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); 445 return false; 446 } 447 448 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { 449 int64_t Type; 450 if (getParser().parseAbsoluteExpression(Type)) 451 return true; 452 453 if (getLexer().isNot(AsmToken::EndOfStatement)) 454 return TokError("unexpected token in directive"); 455 456 Lex(); 457 getStreamer().EmitCOFFSymbolType(Type); 458 return false; 459 } 460 461 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { 462 Lex(); 463 getStreamer().EndCOFFSymbolDef(); 464 return false; 465 } 466 467 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { 468 StringRef SymbolID; 469 if (getParser().parseIdentifier(SymbolID)) 470 return TokError("expected identifier in directive"); 471 472 int64_t Offset = 0; 473 SMLoc OffsetLoc; 474 if (getLexer().is(AsmToken::Plus)) { 475 OffsetLoc = getLexer().getLoc(); 476 if (getParser().parseAbsoluteExpression(Offset)) 477 return true; 478 } 479 480 if (getLexer().isNot(AsmToken::EndOfStatement)) 481 return TokError("unexpected token in directive"); 482 483 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) 484 return Error( 485 OffsetLoc, 486 "invalid '.secrel32' directive offset, can't be less " 487 "than zero or greater than std::numeric_limits<uint32_t>::max()"); 488 489 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 490 491 Lex(); 492 getStreamer().EmitCOFFSecRel32(Symbol, Offset); 493 return false; 494 } 495 496 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) { 497 auto parseOp = [&]() -> bool { 498 StringRef SymbolID; 499 if (getParser().parseIdentifier(SymbolID)) 500 return TokError("expected identifier in directive"); 501 502 int64_t Offset = 0; 503 SMLoc OffsetLoc; 504 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) { 505 OffsetLoc = getLexer().getLoc(); 506 if (getParser().parseAbsoluteExpression(Offset)) 507 return true; 508 } 509 510 if (Offset < std::numeric_limits<int32_t>::min() || 511 Offset > std::numeric_limits<int32_t>::max()) 512 return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less " 513 "than -2147483648 or greater than " 514 "2147483647"); 515 516 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 517 518 getStreamer().EmitCOFFImgRel32(Symbol, Offset); 519 return false; 520 }; 521 522 if (getParser().parseMany(parseOp)) 523 return addErrorSuffix(" in directive"); 524 return false; 525 } 526 527 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) { 528 StringRef SymbolID; 529 if (getParser().parseIdentifier(SymbolID)) 530 return TokError("expected identifier in directive"); 531 532 if (getLexer().isNot(AsmToken::EndOfStatement)) 533 return TokError("unexpected token in directive"); 534 535 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 536 537 Lex(); 538 getStreamer().EmitCOFFSafeSEH(Symbol); 539 return false; 540 } 541 542 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) { 543 StringRef SymbolID; 544 if (getParser().parseIdentifier(SymbolID)) 545 return TokError("expected identifier in directive"); 546 547 if (getLexer().isNot(AsmToken::EndOfStatement)) 548 return TokError("unexpected token in directive"); 549 550 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 551 552 Lex(); 553 getStreamer().EmitCOFFSectionIndex(Symbol); 554 return false; 555 } 556 557 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) { 558 StringRef SymbolID; 559 if (getParser().parseIdentifier(SymbolID)) 560 return TokError("expected identifier in directive"); 561 562 if (getLexer().isNot(AsmToken::EndOfStatement)) 563 return TokError("unexpected token in directive"); 564 565 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 566 567 Lex(); 568 getStreamer().EmitCOFFSymbolIndex(Symbol); 569 return false; 570 } 571 572 /// ::= [ identifier ] 573 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { 574 StringRef TypeId = getTok().getIdentifier(); 575 576 Type = StringSwitch<COFF::COMDATType>(TypeId) 577 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) 578 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) 579 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) 580 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) 581 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 582 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) 583 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) 584 .Default((COFF::COMDATType)0); 585 586 if (Type == 0) 587 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); 588 589 Lex(); 590 591 return false; 592 } 593 594 /// ParseDirectiveLinkOnce 595 /// ::= .linkonce [ identifier ] 596 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { 597 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; 598 if (getLexer().is(AsmToken::Identifier)) 599 if (parseCOMDATType(Type)) 600 return true; 601 602 const MCSectionCOFF *Current = 603 static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); 604 605 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) 606 return Error(Loc, "cannot make section associative with .linkonce"); 607 608 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) 609 return Error(Loc, Twine("section '") + Current->getSectionName() + 610 "' is already linkonce"); 611 612 Current->setSelection(Type); 613 614 if (getLexer().isNot(AsmToken::EndOfStatement)) 615 return TokError("unexpected token in directive"); 616 617 return false; 618 } 619 620 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) { 621 StringRef SymbolID; 622 if (getParser().parseIdentifier(SymbolID)) 623 return true; 624 625 if (getLexer().isNot(AsmToken::EndOfStatement)) 626 return TokError("unexpected token in directive"); 627 628 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID); 629 630 Lex(); 631 getStreamer().EmitWinCFIStartProc(Symbol, Loc); 632 return false; 633 } 634 635 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) { 636 Lex(); 637 getStreamer().EmitWinCFIEndProc(Loc); 638 return false; 639 } 640 641 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) { 642 Lex(); 643 getStreamer().EmitWinCFIStartChained(Loc); 644 return false; 645 } 646 647 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) { 648 Lex(); 649 getStreamer().EmitWinCFIEndChained(Loc); 650 return false; 651 } 652 653 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) { 654 StringRef SymbolID; 655 if (getParser().parseIdentifier(SymbolID)) 656 return true; 657 658 if (getLexer().isNot(AsmToken::Comma)) 659 return TokError("you must specify one or both of @unwind or @except"); 660 Lex(); 661 bool unwind = false, except = false; 662 if (ParseAtUnwindOrAtExcept(unwind, except)) 663 return true; 664 if (getLexer().is(AsmToken::Comma)) { 665 Lex(); 666 if (ParseAtUnwindOrAtExcept(unwind, except)) 667 return true; 668 } 669 if (getLexer().isNot(AsmToken::EndOfStatement)) 670 return TokError("unexpected token in directive"); 671 672 MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID); 673 674 Lex(); 675 getStreamer().EmitWinEHHandler(handler, unwind, except, Loc); 676 return false; 677 } 678 679 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { 680 Lex(); 681 getStreamer().EmitWinEHHandlerData(); 682 return false; 683 } 684 685 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) { 686 unsigned Reg = 0; 687 if (ParseSEHRegisterNumber(Reg)) 688 return true; 689 690 if (getLexer().isNot(AsmToken::EndOfStatement)) 691 return TokError("unexpected token in directive"); 692 693 Lex(); 694 getStreamer().EmitWinCFIPushReg(Reg, Loc); 695 return false; 696 } 697 698 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) { 699 unsigned Reg = 0; 700 int64_t Off; 701 if (ParseSEHRegisterNumber(Reg)) 702 return true; 703 if (getLexer().isNot(AsmToken::Comma)) 704 return TokError("you must specify a stack pointer offset"); 705 706 Lex(); 707 if (getParser().parseAbsoluteExpression(Off)) 708 return true; 709 710 if (getLexer().isNot(AsmToken::EndOfStatement)) 711 return TokError("unexpected token in directive"); 712 713 Lex(); 714 getStreamer().EmitWinCFISetFrame(Reg, Off, Loc); 715 return false; 716 } 717 718 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { 719 int64_t Size; 720 if (getParser().parseAbsoluteExpression(Size)) 721 return true; 722 723 if (getLexer().isNot(AsmToken::EndOfStatement)) 724 return TokError("unexpected token in directive"); 725 726 Lex(); 727 getStreamer().EmitWinCFIAllocStack(Size, Loc); 728 return false; 729 } 730 731 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) { 732 unsigned Reg = 0; 733 int64_t Off; 734 if (ParseSEHRegisterNumber(Reg)) 735 return true; 736 if (getLexer().isNot(AsmToken::Comma)) 737 return TokError("you must specify an offset on the stack"); 738 739 Lex(); 740 if (getParser().parseAbsoluteExpression(Off)) 741 return true; 742 743 if (getLexer().isNot(AsmToken::EndOfStatement)) 744 return TokError("unexpected token in directive"); 745 746 Lex(); 747 // FIXME: Err on %xmm* registers 748 getStreamer().EmitWinCFISaveReg(Reg, Off, Loc); 749 return false; 750 } 751 752 // FIXME: This method is inherently x86-specific. It should really be in the 753 // x86 backend. 754 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) { 755 unsigned Reg = 0; 756 int64_t Off; 757 if (ParseSEHRegisterNumber(Reg)) 758 return true; 759 if (getLexer().isNot(AsmToken::Comma)) 760 return TokError("you must specify an offset on the stack"); 761 762 Lex(); 763 if (getParser().parseAbsoluteExpression(Off)) 764 return true; 765 766 if (getLexer().isNot(AsmToken::EndOfStatement)) 767 return TokError("unexpected token in directive"); 768 769 Lex(); 770 // FIXME: Err on non-%xmm* registers 771 getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc); 772 return false; 773 } 774 775 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) { 776 bool Code = false; 777 StringRef CodeID; 778 if (getLexer().is(AsmToken::At)) { 779 SMLoc startLoc = getLexer().getLoc(); 780 Lex(); 781 if (!getParser().parseIdentifier(CodeID)) { 782 if (CodeID != "code") 783 return Error(startLoc, "expected @code"); 784 Code = true; 785 } 786 } 787 788 if (getLexer().isNot(AsmToken::EndOfStatement)) 789 return TokError("unexpected token in directive"); 790 791 Lex(); 792 getStreamer().EmitWinCFIPushFrame(Code, Loc); 793 return false; 794 } 795 796 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { 797 Lex(); 798 getStreamer().EmitWinCFIEndProlog(Loc); 799 return false; 800 } 801 802 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { 803 StringRef identifier; 804 if (getLexer().isNot(AsmToken::At)) 805 return TokError("a handler attribute must begin with '@'"); 806 SMLoc startLoc = getLexer().getLoc(); 807 Lex(); 808 if (getParser().parseIdentifier(identifier)) 809 return Error(startLoc, "expected @unwind or @except"); 810 if (identifier == "unwind") 811 unwind = true; 812 else if (identifier == "except") 813 except = true; 814 else 815 return Error(startLoc, "expected @unwind or @except"); 816 return false; 817 } 818 819 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { 820 SMLoc startLoc = getLexer().getLoc(); 821 if (getLexer().is(AsmToken::Percent)) { 822 const MCRegisterInfo *MRI = getContext().getRegisterInfo(); 823 SMLoc endLoc; 824 unsigned LLVMRegNo; 825 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) 826 return true; 827 828 #if 0 829 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering 830 // violation so this validation code is disabled. 831 832 // Check that this is a non-volatile register. 833 const unsigned *NVRegs = TAI.getCalleeSavedRegs(); 834 unsigned i; 835 for (i = 0; NVRegs[i] != 0; ++i) 836 if (NVRegs[i] == LLVMRegNo) 837 break; 838 if (NVRegs[i] == 0) 839 return Error(startLoc, "expected non-volatile register"); 840 #endif 841 842 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo); 843 if (SEHRegNo < 0) 844 return Error(startLoc,"register can't be represented in SEH unwind info"); 845 RegNo = SEHRegNo; 846 } 847 else { 848 int64_t n; 849 if (getParser().parseAbsoluteExpression(n)) 850 return true; 851 if (n > 15) 852 return Error(startLoc, "register number is too high"); 853 RegNo = n; 854 } 855 856 return false; 857 } 858 859 namespace llvm { 860 861 MCAsmParserExtension *createCOFFAsmParser() { 862 return new COFFAsmParser; 863 } 864 865 } // end namespace llvm 866