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