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/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"
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);
34 bool ParseSectionSwitch(StringRef Section,
35 unsigned Characteristics,
38 virtual void Initialize(MCAsmParser &Parser) {
39 // Call the base implementation.
40 MCAsmParserExtension::Initialize(Parser);
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");
51 // Win64 EH directives.
52 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
54 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
56 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
58 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
60 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
62 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
64 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
66 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
68 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
70 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
72 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
74 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
78 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
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());
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());
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());
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);
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);
124 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
125 bool ParseSEHRegisterNumber(unsigned &RegNo);
126 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
131 } // end annonomous namespace.
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)) {
144 if (getParser().parseIdentifier(Name))
145 return TokError("expected identifier in directive");
147 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
149 getStreamer().EmitSymbolAttribute(Sym, Attr);
151 if (getLexer().is(AsmToken::EndOfStatement))
154 if (getLexer().isNot(AsmToken::Comma))
155 return TokError("unexpected token in directive");
164 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
165 unsigned Characteristics,
167 if (getLexer().isNot(AsmToken::EndOfStatement))
168 return TokError("unexpected token in section switching directive");
171 getStreamer().SwitchSection(getContext().getCOFFSection(
172 Section, Characteristics, Kind));
177 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
178 StringRef SymbolName;
180 if (getParser().parseIdentifier(SymbolName))
181 return TokError("expected identifier in directive");
183 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
185 getStreamer().BeginCOFFSymbolDef(Sym);
191 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
192 int64_t SymbolStorageClass;
193 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
196 if (getLexer().isNot(AsmToken::EndOfStatement))
197 return TokError("unexpected token in directive");
200 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
204 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
206 if (getParser().parseAbsoluteExpression(Type))
209 if (getLexer().isNot(AsmToken::EndOfStatement))
210 return TokError("unexpected token in directive");
213 getStreamer().EmitCOFFSymbolType(Type);
217 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
219 getStreamer().EndCOFFSymbolDef();
223 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
225 if (getParser().parseIdentifier(SymbolID))
228 if (getLexer().isNot(AsmToken::EndOfStatement))
229 return TokError("unexpected token in directive");
231 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
234 getStreamer().EmitCOFFSecRel32(Symbol);
238 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
240 if (getParser().parseIdentifier(SymbolID))
243 if (getLexer().isNot(AsmToken::EndOfStatement))
244 return TokError("unexpected token in directive");
246 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
249 getStreamer().EmitWin64EHStartProc(Symbol);
253 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
255 getStreamer().EmitWin64EHEndProc();
259 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
261 getStreamer().EmitWin64EHStartChained();
265 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
267 getStreamer().EmitWin64EHEndChained();
271 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
273 if (getParser().parseIdentifier(SymbolID))
276 if (getLexer().isNot(AsmToken::Comma))
277 return TokError("you must specify one or both of @unwind or @except");
279 bool unwind = false, except = false;
280 if (ParseAtUnwindOrAtExcept(unwind, except))
282 if (getLexer().is(AsmToken::Comma)) {
284 if (ParseAtUnwindOrAtExcept(unwind, except))
287 if (getLexer().isNot(AsmToken::EndOfStatement))
288 return TokError("unexpected token in directive");
290 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
293 getStreamer().EmitWin64EHHandler(handler, unwind, except);
297 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
299 getStreamer().EmitWin64EHHandlerData();
303 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
305 if (ParseSEHRegisterNumber(Reg))
308 if (getLexer().isNot(AsmToken::EndOfStatement))
309 return TokError("unexpected token in directive");
312 getStreamer().EmitWin64EHPushReg(Reg);
316 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
319 if (ParseSEHRegisterNumber(Reg))
321 if (getLexer().isNot(AsmToken::Comma))
322 return TokError("you must specify a stack pointer offset");
325 SMLoc startLoc = getLexer().getLoc();
326 if (getParser().parseAbsoluteExpression(Off))
330 return Error(startLoc, "offset is not a multiple of 16");
332 if (getLexer().isNot(AsmToken::EndOfStatement))
333 return TokError("unexpected token in directive");
336 getStreamer().EmitWin64EHSetFrame(Reg, Off);
340 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
342 SMLoc startLoc = getLexer().getLoc();
343 if (getParser().parseAbsoluteExpression(Size))
347 return Error(startLoc, "size is not a multiple of 8");
349 if (getLexer().isNot(AsmToken::EndOfStatement))
350 return TokError("unexpected token in directive");
353 getStreamer().EmitWin64EHAllocStack(Size);
357 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
360 if (ParseSEHRegisterNumber(Reg))
362 if (getLexer().isNot(AsmToken::Comma))
363 return TokError("you must specify an offset on the stack");
366 SMLoc startLoc = getLexer().getLoc();
367 if (getParser().parseAbsoluteExpression(Off))
371 return Error(startLoc, "size is not a multiple of 8");
373 if (getLexer().isNot(AsmToken::EndOfStatement))
374 return TokError("unexpected token in directive");
377 // FIXME: Err on %xmm* registers
378 getStreamer().EmitWin64EHSaveReg(Reg, Off);
382 // FIXME: This method is inherently x86-specific. It should really be in the
384 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
387 if (ParseSEHRegisterNumber(Reg))
389 if (getLexer().isNot(AsmToken::Comma))
390 return TokError("you must specify an offset on the stack");
393 SMLoc startLoc = getLexer().getLoc();
394 if (getParser().parseAbsoluteExpression(Off))
397 if (getLexer().isNot(AsmToken::EndOfStatement))
398 return TokError("unexpected token in directive");
401 return Error(startLoc, "offset is not a multiple of 16");
404 // FIXME: Err on non-%xmm* registers
405 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
409 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
412 if (getLexer().is(AsmToken::At)) {
413 SMLoc startLoc = getLexer().getLoc();
415 if (!getParser().parseIdentifier(CodeID)) {
416 if (CodeID != "code")
417 return Error(startLoc, "expected @code");
422 if (getLexer().isNot(AsmToken::EndOfStatement))
423 return TokError("unexpected token in directive");
426 getStreamer().EmitWin64EHPushFrame(Code);
430 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
432 getStreamer().EmitWin64EHEndProlog();
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();
442 if (getParser().parseIdentifier(identifier))
443 return Error(startLoc, "expected @unwind or @except");
444 if (identifier == "unwind")
446 else if (identifier == "except")
449 return Error(startLoc, "expected @unwind or @except");
453 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
454 SMLoc startLoc = getLexer().getLoc();
455 if (getLexer().is(AsmToken::Percent)) {
456 const MCRegisterInfo &MRI = getContext().getRegisterInfo();
459 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
463 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
464 // violation so this validation code is disabled.
466 // Check that this is a non-volatile register.
467 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
469 for (i = 0; NVRegs[i] != 0; ++i)
470 if (NVRegs[i] == LLVMRegNo)
473 return Error(startLoc, "expected non-volatile register");
476 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
478 return Error(startLoc,"register can't be represented in SEH unwind info");
483 if (getParser().parseAbsoluteExpression(n))
486 return Error(startLoc, "register number is too high");
495 MCAsmParserExtension *createCOFFAsmParser() {
496 return new COFFAsmParser;