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