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