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