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