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/MCParser/MCAsmLexer.h" 17 #include "llvm/MC/MCRegisterInfo.h" 18 #include "llvm/MC/MCSectionCOFF.h" 19 #include "llvm/MC/MCStreamer.h" 20 #include "llvm/MC/MCTargetAsmParser.h" 21 #include "llvm/Support/COFF.h" 22 using namespace llvm; 23 24 namespace { 25 26 class COFFAsmParser : public MCAsmParserExtension { 27 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> 28 void addDirectiveHandler(StringRef Directive) { 29 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 30 this, HandleDirective<COFFAsmParser, HandlerMethod>); 31 getParser().addDirectiveHandler(Directive, Handler); 32 } 33 34 bool ParseSectionSwitch(StringRef Section, 35 unsigned Characteristics, 36 SectionKind Kind); 37 38 virtual void Initialize(MCAsmParser &Parser) { 39 // Call the base implementation. 40 MCAsmParserExtension::Initialize(Parser); 41 42 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); 43 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); 44 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); 45 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); 46 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); 47 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); 48 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); 49 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); 50 51 // Win64 EH directives. 52 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( 53 ".seh_proc"); 54 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>( 55 ".seh_endproc"); 56 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>( 57 ".seh_startchained"); 58 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>( 59 ".seh_endchained"); 60 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>( 61 ".seh_handler"); 62 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>( 63 ".seh_handlerdata"); 64 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>( 65 ".seh_pushreg"); 66 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>( 67 ".seh_setframe"); 68 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( 69 ".seh_stackalloc"); 70 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>( 71 ".seh_savereg"); 72 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>( 73 ".seh_savexmm"); 74 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>( 75 ".seh_pushframe"); 76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( 77 ".seh_endprologue"); 78 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); 79 } 80 81 bool ParseSectionDirectiveText(StringRef, SMLoc) { 82 return ParseSectionSwitch(".text", 83 COFF::IMAGE_SCN_CNT_CODE 84 | COFF::IMAGE_SCN_MEM_EXECUTE 85 | COFF::IMAGE_SCN_MEM_READ, 86 SectionKind::getText()); 87 } 88 bool ParseSectionDirectiveData(StringRef, SMLoc) { 89 return ParseSectionSwitch(".data", 90 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA 91 | COFF::IMAGE_SCN_MEM_READ 92 | COFF::IMAGE_SCN_MEM_WRITE, 93 SectionKind::getDataRel()); 94 } 95 bool ParseSectionDirectiveBSS(StringRef, SMLoc) { 96 return ParseSectionSwitch(".bss", 97 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA 98 | COFF::IMAGE_SCN_MEM_READ 99 | COFF::IMAGE_SCN_MEM_WRITE, 100 SectionKind::getBSS()); 101 } 102 103 bool ParseDirectiveDef(StringRef, SMLoc); 104 bool ParseDirectiveScl(StringRef, SMLoc); 105 bool ParseDirectiveType(StringRef, SMLoc); 106 bool ParseDirectiveEndef(StringRef, SMLoc); 107 bool ParseDirectiveSecRel32(StringRef, SMLoc); 108 109 // Win64 EH directives. 110 bool ParseSEHDirectiveStartProc(StringRef, SMLoc); 111 bool ParseSEHDirectiveEndProc(StringRef, SMLoc); 112 bool ParseSEHDirectiveStartChained(StringRef, SMLoc); 113 bool ParseSEHDirectiveEndChained(StringRef, SMLoc); 114 bool ParseSEHDirectiveHandler(StringRef, SMLoc); 115 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc); 116 bool ParseSEHDirectivePushReg(StringRef, SMLoc); 117 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc); 118 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); 119 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc); 120 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc); 121 bool ParseSEHDirectivePushFrame(StringRef, SMLoc); 122 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc); 123 124 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except); 125 bool ParseSEHRegisterNumber(unsigned &RegNo); 126 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc); 127 public: 128 COFFAsmParser() {} 129 }; 130 131 } // end annonomous namespace. 132 133 /// ParseDirectiveSymbolAttribute 134 /// ::= { ".weak", ... } [ identifier ( , identifier )* ] 135 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 136 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 137 .Case(".weak", MCSA_Weak) 138 .Default(MCSA_Invalid); 139 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 140 if (getLexer().isNot(AsmToken::EndOfStatement)) { 141 for (;;) { 142 StringRef Name; 143 144 if (getParser().parseIdentifier(Name)) 145 return TokError("expected identifier in directive"); 146 147 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); 148 149 getStreamer().EmitSymbolAttribute(Sym, Attr); 150 151 if (getLexer().is(AsmToken::EndOfStatement)) 152 break; 153 154 if (getLexer().isNot(AsmToken::Comma)) 155 return TokError("unexpected token in directive"); 156 Lex(); 157 } 158 } 159 160 Lex(); 161 return false; 162 } 163 164 bool COFFAsmParser::ParseSectionSwitch(StringRef Section, 165 unsigned Characteristics, 166 SectionKind Kind) { 167 if (getLexer().isNot(AsmToken::EndOfStatement)) 168 return TokError("unexpected token in section switching directive"); 169 Lex(); 170 171 getStreamer().SwitchSection(getContext().getCOFFSection( 172 Section, Characteristics, Kind)); 173 174 return false; 175 } 176 177 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { 178 StringRef SymbolName; 179 180 if (getParser().parseIdentifier(SymbolName)) 181 return TokError("expected identifier in directive"); 182 183 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); 184 185 getStreamer().BeginCOFFSymbolDef(Sym); 186 187 Lex(); 188 return false; 189 } 190 191 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { 192 int64_t SymbolStorageClass; 193 if (getParser().parseAbsoluteExpression(SymbolStorageClass)) 194 return true; 195 196 if (getLexer().isNot(AsmToken::EndOfStatement)) 197 return TokError("unexpected token in directive"); 198 199 Lex(); 200 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); 201 return false; 202 } 203 204 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { 205 int64_t Type; 206 if (getParser().parseAbsoluteExpression(Type)) 207 return true; 208 209 if (getLexer().isNot(AsmToken::EndOfStatement)) 210 return TokError("unexpected token in directive"); 211 212 Lex(); 213 getStreamer().EmitCOFFSymbolType(Type); 214 return false; 215 } 216 217 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { 218 Lex(); 219 getStreamer().EndCOFFSymbolDef(); 220 return false; 221 } 222 223 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { 224 StringRef SymbolID; 225 if (getParser().parseIdentifier(SymbolID)) 226 return true; 227 228 if (getLexer().isNot(AsmToken::EndOfStatement)) 229 return TokError("unexpected token in directive"); 230 231 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); 232 233 Lex(); 234 getStreamer().EmitCOFFSecRel32(Symbol); 235 return false; 236 } 237 238 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { 239 StringRef SymbolID; 240 if (getParser().parseIdentifier(SymbolID)) 241 return true; 242 243 if (getLexer().isNot(AsmToken::EndOfStatement)) 244 return TokError("unexpected token in directive"); 245 246 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); 247 248 Lex(); 249 getStreamer().EmitWin64EHStartProc(Symbol); 250 return false; 251 } 252 253 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) { 254 Lex(); 255 getStreamer().EmitWin64EHEndProc(); 256 return false; 257 } 258 259 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) { 260 Lex(); 261 getStreamer().EmitWin64EHStartChained(); 262 return false; 263 } 264 265 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) { 266 Lex(); 267 getStreamer().EmitWin64EHEndChained(); 268 return false; 269 } 270 271 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) { 272 StringRef SymbolID; 273 if (getParser().parseIdentifier(SymbolID)) 274 return true; 275 276 if (getLexer().isNot(AsmToken::Comma)) 277 return TokError("you must specify one or both of @unwind or @except"); 278 Lex(); 279 bool unwind = false, except = false; 280 if (ParseAtUnwindOrAtExcept(unwind, except)) 281 return true; 282 if (getLexer().is(AsmToken::Comma)) { 283 Lex(); 284 if (ParseAtUnwindOrAtExcept(unwind, except)) 285 return true; 286 } 287 if (getLexer().isNot(AsmToken::EndOfStatement)) 288 return TokError("unexpected token in directive"); 289 290 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID); 291 292 Lex(); 293 getStreamer().EmitWin64EHHandler(handler, unwind, except); 294 return false; 295 } 296 297 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) { 298 Lex(); 299 getStreamer().EmitWin64EHHandlerData(); 300 return false; 301 } 302 303 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) { 304 unsigned Reg; 305 if (ParseSEHRegisterNumber(Reg)) 306 return true; 307 308 if (getLexer().isNot(AsmToken::EndOfStatement)) 309 return TokError("unexpected token in directive"); 310 311 Lex(); 312 getStreamer().EmitWin64EHPushReg(Reg); 313 return false; 314 } 315 316 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) { 317 unsigned Reg; 318 int64_t Off; 319 if (ParseSEHRegisterNumber(Reg)) 320 return true; 321 if (getLexer().isNot(AsmToken::Comma)) 322 return TokError("you must specify a stack pointer offset"); 323 324 Lex(); 325 SMLoc startLoc = getLexer().getLoc(); 326 if (getParser().parseAbsoluteExpression(Off)) 327 return true; 328 329 if (Off & 0x0F) 330 return Error(startLoc, "offset is not a multiple of 16"); 331 332 if (getLexer().isNot(AsmToken::EndOfStatement)) 333 return TokError("unexpected token in directive"); 334 335 Lex(); 336 getStreamer().EmitWin64EHSetFrame(Reg, Off); 337 return false; 338 } 339 340 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) { 341 int64_t Size; 342 SMLoc startLoc = getLexer().getLoc(); 343 if (getParser().parseAbsoluteExpression(Size)) 344 return true; 345 346 if (Size & 7) 347 return Error(startLoc, "size is not a multiple of 8"); 348 349 if (getLexer().isNot(AsmToken::EndOfStatement)) 350 return TokError("unexpected token in directive"); 351 352 Lex(); 353 getStreamer().EmitWin64EHAllocStack(Size); 354 return false; 355 } 356 357 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) { 358 unsigned Reg; 359 int64_t Off; 360 if (ParseSEHRegisterNumber(Reg)) 361 return true; 362 if (getLexer().isNot(AsmToken::Comma)) 363 return TokError("you must specify an offset on the stack"); 364 365 Lex(); 366 SMLoc startLoc = getLexer().getLoc(); 367 if (getParser().parseAbsoluteExpression(Off)) 368 return true; 369 370 if (Off & 7) 371 return Error(startLoc, "size is not a multiple of 8"); 372 373 if (getLexer().isNot(AsmToken::EndOfStatement)) 374 return TokError("unexpected token in directive"); 375 376 Lex(); 377 // FIXME: Err on %xmm* registers 378 getStreamer().EmitWin64EHSaveReg(Reg, Off); 379 return false; 380 } 381 382 // FIXME: This method is inherently x86-specific. It should really be in the 383 // x86 backend. 384 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) { 385 unsigned Reg; 386 int64_t Off; 387 if (ParseSEHRegisterNumber(Reg)) 388 return true; 389 if (getLexer().isNot(AsmToken::Comma)) 390 return TokError("you must specify an offset on the stack"); 391 392 Lex(); 393 SMLoc startLoc = getLexer().getLoc(); 394 if (getParser().parseAbsoluteExpression(Off)) 395 return true; 396 397 if (getLexer().isNot(AsmToken::EndOfStatement)) 398 return TokError("unexpected token in directive"); 399 400 if (Off & 0x0F) 401 return Error(startLoc, "offset is not a multiple of 16"); 402 403 Lex(); 404 // FIXME: Err on non-%xmm* registers 405 getStreamer().EmitWin64EHSaveXMM(Reg, Off); 406 return false; 407 } 408 409 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) { 410 bool Code = false; 411 StringRef CodeID; 412 if (getLexer().is(AsmToken::At)) { 413 SMLoc startLoc = getLexer().getLoc(); 414 Lex(); 415 if (!getParser().parseIdentifier(CodeID)) { 416 if (CodeID != "code") 417 return Error(startLoc, "expected @code"); 418 Code = true; 419 } 420 } 421 422 if (getLexer().isNot(AsmToken::EndOfStatement)) 423 return TokError("unexpected token in directive"); 424 425 Lex(); 426 getStreamer().EmitWin64EHPushFrame(Code); 427 return false; 428 } 429 430 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) { 431 Lex(); 432 getStreamer().EmitWin64EHEndProlog(); 433 return false; 434 } 435 436 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) { 437 StringRef identifier; 438 if (getLexer().isNot(AsmToken::At)) 439 return TokError("a handler attribute must begin with '@'"); 440 SMLoc startLoc = getLexer().getLoc(); 441 Lex(); 442 if (getParser().parseIdentifier(identifier)) 443 return Error(startLoc, "expected @unwind or @except"); 444 if (identifier == "unwind") 445 unwind = true; 446 else if (identifier == "except") 447 except = true; 448 else 449 return Error(startLoc, "expected @unwind or @except"); 450 return false; 451 } 452 453 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { 454 SMLoc startLoc = getLexer().getLoc(); 455 if (getLexer().is(AsmToken::Percent)) { 456 const MCRegisterInfo &MRI = getContext().getRegisterInfo(); 457 SMLoc endLoc; 458 unsigned LLVMRegNo; 459 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) 460 return true; 461 462 #if 0 463 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering 464 // violation so this validation code is disabled. 465 466 // Check that this is a non-volatile register. 467 const unsigned *NVRegs = TAI.getCalleeSavedRegs(); 468 unsigned i; 469 for (i = 0; NVRegs[i] != 0; ++i) 470 if (NVRegs[i] == LLVMRegNo) 471 break; 472 if (NVRegs[i] == 0) 473 return Error(startLoc, "expected non-volatile register"); 474 #endif 475 476 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo); 477 if (SEHRegNo < 0) 478 return Error(startLoc,"register can't be represented in SEH unwind info"); 479 RegNo = SEHRegNo; 480 } 481 else { 482 int64_t n; 483 if (getParser().parseAbsoluteExpression(n)) 484 return true; 485 if (n > 15) 486 return Error(startLoc, "register number is too high"); 487 RegNo = n; 488 } 489 490 return false; 491 } 492 493 namespace llvm { 494 495 MCAsmParserExtension *createCOFFAsmParser() { 496 return new COFFAsmParser; 497 } 498 499 } 500