1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
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>);
33 bool ParseSectionSwitch(StringRef Section,
34 unsigned Characteristics,
37 virtual void Initialize(MCAsmParser &Parser) {
38 // Call the base implementation.
39 MCAsmParserExtension::Initialize(Parser);
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");
50 // Win64 EH directives.
51 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
53 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
55 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
57 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
59 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
61 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
63 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
65 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
67 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
69 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
71 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
73 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
75 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
77 AddDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
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());
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());
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());
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);
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);
123 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
124 bool ParseSEHRegisterNumber(unsigned &RegNo);
125 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
130 } // end annonomous namespace.
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)) {
143 if (getParser().ParseIdentifier(Name))
144 return TokError("expected identifier in directive");
146 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
148 getStreamer().EmitSymbolAttribute(Sym, Attr);
150 if (getLexer().is(AsmToken::EndOfStatement))
153 if (getLexer().isNot(AsmToken::Comma))
154 return TokError("unexpected token in directive");
163 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
164 unsigned Characteristics,
166 if (getLexer().isNot(AsmToken::EndOfStatement))
167 return TokError("unexpected token in section switching directive");
170 getStreamer().SwitchSection(getContext().getCOFFSection(
171 Section, Characteristics, Kind));
176 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
177 StringRef SymbolName;
179 if (getParser().ParseIdentifier(SymbolName))
180 return TokError("expected identifier in directive");
182 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
184 getStreamer().BeginCOFFSymbolDef(Sym);
190 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
191 int64_t SymbolStorageClass;
192 if (getParser().ParseAbsoluteExpression(SymbolStorageClass))
195 if (getLexer().isNot(AsmToken::EndOfStatement))
196 return TokError("unexpected token in directive");
199 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
203 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
205 if (getParser().ParseAbsoluteExpression(Type))
208 if (getLexer().isNot(AsmToken::EndOfStatement))
209 return TokError("unexpected token in directive");
212 getStreamer().EmitCOFFSymbolType(Type);
216 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
218 getStreamer().EndCOFFSymbolDef();
222 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
224 if (getParser().ParseIdentifier(SymbolID))
227 if (getLexer().isNot(AsmToken::EndOfStatement))
228 return TokError("unexpected token in directive");
230 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
233 getStreamer().EmitCOFFSecRel32(Symbol);
237 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
239 if (getParser().ParseIdentifier(SymbolID))
242 if (getLexer().isNot(AsmToken::EndOfStatement))
243 return TokError("unexpected token in directive");
245 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
248 getStreamer().EmitWin64EHStartProc(Symbol);
252 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
254 getStreamer().EmitWin64EHEndProc();
258 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
260 getStreamer().EmitWin64EHStartChained();
264 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
266 getStreamer().EmitWin64EHEndChained();
270 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
272 if (getParser().ParseIdentifier(SymbolID))
275 if (getLexer().isNot(AsmToken::Comma))
276 return TokError("you must specify one or both of @unwind or @except");
278 bool unwind = false, except = false;
279 if (ParseAtUnwindOrAtExcept(unwind, except))
281 if (getLexer().is(AsmToken::Comma)) {
283 if (ParseAtUnwindOrAtExcept(unwind, except))
286 if (getLexer().isNot(AsmToken::EndOfStatement))
287 return TokError("unexpected token in directive");
289 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
292 getStreamer().EmitWin64EHHandler(handler, unwind, except);
296 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
298 getStreamer().EmitWin64EHHandlerData();
302 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
304 if (ParseSEHRegisterNumber(Reg))
307 if (getLexer().isNot(AsmToken::EndOfStatement))
308 return TokError("unexpected token in directive");
311 getStreamer().EmitWin64EHPushReg(Reg);
315 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
318 if (ParseSEHRegisterNumber(Reg))
320 if (getLexer().isNot(AsmToken::Comma))
321 return TokError("you must specify a stack pointer offset");
324 SMLoc startLoc = getLexer().getLoc();
325 if (getParser().ParseAbsoluteExpression(Off))
329 return Error(startLoc, "offset is not a multiple of 16");
331 if (getLexer().isNot(AsmToken::EndOfStatement))
332 return TokError("unexpected token in directive");
335 getStreamer().EmitWin64EHSetFrame(Reg, Off);
339 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
341 SMLoc startLoc = getLexer().getLoc();
342 if (getParser().ParseAbsoluteExpression(Size))
346 return Error(startLoc, "size is not a multiple of 8");
348 if (getLexer().isNot(AsmToken::EndOfStatement))
349 return TokError("unexpected token in directive");
352 getStreamer().EmitWin64EHAllocStack(Size);
356 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
359 if (ParseSEHRegisterNumber(Reg))
361 if (getLexer().isNot(AsmToken::Comma))
362 return TokError("you must specify an offset on the stack");
365 SMLoc startLoc = getLexer().getLoc();
366 if (getParser().ParseAbsoluteExpression(Off))
370 return Error(startLoc, "size is not a multiple of 8");
372 if (getLexer().isNot(AsmToken::EndOfStatement))
373 return TokError("unexpected token in directive");
376 // FIXME: Err on %xmm* registers
377 getStreamer().EmitWin64EHSaveReg(Reg, Off);
381 // FIXME: This method is inherently x86-specific. It should really be in the
383 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
386 if (ParseSEHRegisterNumber(Reg))
388 if (getLexer().isNot(AsmToken::Comma))
389 return TokError("you must specify an offset on the stack");
392 SMLoc startLoc = getLexer().getLoc();
393 if (getParser().ParseAbsoluteExpression(Off))
396 if (getLexer().isNot(AsmToken::EndOfStatement))
397 return TokError("unexpected token in directive");
400 return Error(startLoc, "offset is not a multiple of 16");
403 // FIXME: Err on non-%xmm* registers
404 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
408 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
411 if (getLexer().is(AsmToken::At)) {
412 SMLoc startLoc = getLexer().getLoc();
414 if (!getParser().ParseIdentifier(CodeID)) {
415 if (CodeID != "code")
416 return Error(startLoc, "expected @code");
421 if (getLexer().isNot(AsmToken::EndOfStatement))
422 return TokError("unexpected token in directive");
425 getStreamer().EmitWin64EHPushFrame(Code);
429 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
431 getStreamer().EmitWin64EHEndProlog();
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();
441 if (getParser().ParseIdentifier(identifier))
442 return Error(startLoc, "expected @unwind or @except");
443 if (identifier == "unwind")
445 else if (identifier == "except")
448 return Error(startLoc, "expected @unwind or @except");
452 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
453 SMLoc startLoc = getLexer().getLoc();
454 if (getLexer().is(AsmToken::Percent)) {
455 const MCRegisterInfo &MRI = getContext().getRegisterInfo();
458 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
462 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
463 // violation so this validation code is disabled.
465 // Check that this is a non-volatile register.
466 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
468 for (i = 0; NVRegs[i] != 0; ++i)
469 if (NVRegs[i] == LLVMRegNo)
472 return Error(startLoc, "expected non-volatile register");
475 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
477 return Error(startLoc,"register can't be represented in SEH unwind info");
482 if (getParser().ParseAbsoluteExpression(n))
485 return Error(startLoc, "register number is too high");
494 MCAsmParserExtension *createCOFFAsmParser() {
495 return new COFFAsmParser;