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");
49 // Win64 EH directives.
50 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
52 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
54 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
56 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
58 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
60 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
62 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
64 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
66 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
68 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
70 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
72 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
74 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
76 AddDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
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());
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());
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());
101 bool ParseDirectiveDef(StringRef, SMLoc);
102 bool ParseDirectiveScl(StringRef, SMLoc);
103 bool ParseDirectiveType(StringRef, SMLoc);
104 bool ParseDirectiveEndef(StringRef, SMLoc);
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);
121 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
122 bool ParseSEHRegisterNumber(unsigned &RegNo);
123 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
128 } // end annonomous namespace.
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)) {
141 if (getParser().ParseIdentifier(Name))
142 return TokError("expected identifier in directive");
144 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
146 getStreamer().EmitSymbolAttribute(Sym, Attr);
148 if (getLexer().is(AsmToken::EndOfStatement))
151 if (getLexer().isNot(AsmToken::Comma))
152 return TokError("unexpected token in directive");
161 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
162 unsigned Characteristics,
164 if (getLexer().isNot(AsmToken::EndOfStatement))
165 return TokError("unexpected token in section switching directive");
168 getStreamer().SwitchSection(getContext().getCOFFSection(
169 Section, Characteristics, Kind));
174 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
175 StringRef SymbolName;
177 if (getParser().ParseIdentifier(SymbolName))
178 return TokError("expected identifier in directive");
180 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
182 getStreamer().BeginCOFFSymbolDef(Sym);
188 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
189 int64_t SymbolStorageClass;
190 if (getParser().ParseAbsoluteExpression(SymbolStorageClass))
193 if (getLexer().isNot(AsmToken::EndOfStatement))
194 return TokError("unexpected token in directive");
197 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
201 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
203 if (getParser().ParseAbsoluteExpression(Type))
206 if (getLexer().isNot(AsmToken::EndOfStatement))
207 return TokError("unexpected token in directive");
210 getStreamer().EmitCOFFSymbolType(Type);
214 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
216 getStreamer().EndCOFFSymbolDef();
220 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
222 if (getParser().ParseIdentifier(SymbolID))
225 if (getLexer().isNot(AsmToken::EndOfStatement))
226 return TokError("unexpected token in directive");
228 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
231 getStreamer().EmitWin64EHStartProc(Symbol);
235 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
237 getStreamer().EmitWin64EHEndProc();
241 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
243 getStreamer().EmitWin64EHStartChained();
247 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
249 getStreamer().EmitWin64EHEndChained();
253 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
255 if (getParser().ParseIdentifier(SymbolID))
258 if (getLexer().isNot(AsmToken::Comma))
259 return TokError("you must specify one or both of @unwind or @except");
261 bool unwind = false, except = false;
262 if (ParseAtUnwindOrAtExcept(unwind, except))
264 if (getLexer().is(AsmToken::Comma)) {
266 if (ParseAtUnwindOrAtExcept(unwind, except))
269 if (getLexer().isNot(AsmToken::EndOfStatement))
270 return TokError("unexpected token in directive");
272 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
275 getStreamer().EmitWin64EHHandler(handler, unwind, except);
279 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
281 getStreamer().EmitWin64EHHandlerData();
285 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
287 if (ParseSEHRegisterNumber(Reg))
290 if (getLexer().isNot(AsmToken::EndOfStatement))
291 return TokError("unexpected token in directive");
294 getStreamer().EmitWin64EHPushReg(Reg);
298 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
301 if (ParseSEHRegisterNumber(Reg))
303 if (getLexer().isNot(AsmToken::Comma))
304 return TokError("you must specify a stack pointer offset");
307 SMLoc startLoc = getLexer().getLoc();
308 if (getParser().ParseAbsoluteExpression(Off))
312 return Error(startLoc, "offset is not a multiple of 16");
314 if (getLexer().isNot(AsmToken::EndOfStatement))
315 return TokError("unexpected token in directive");
318 getStreamer().EmitWin64EHSetFrame(Reg, Off);
322 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
324 SMLoc startLoc = getLexer().getLoc();
325 if (getParser().ParseAbsoluteExpression(Size))
329 return Error(startLoc, "size is not a multiple of 8");
331 if (getLexer().isNot(AsmToken::EndOfStatement))
332 return TokError("unexpected token in directive");
335 getStreamer().EmitWin64EHAllocStack(Size);
339 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
342 if (ParseSEHRegisterNumber(Reg))
344 if (getLexer().isNot(AsmToken::Comma))
345 return TokError("you must specify an offset on the stack");
348 SMLoc startLoc = getLexer().getLoc();
349 if (getParser().ParseAbsoluteExpression(Off))
353 return Error(startLoc, "size is not a multiple of 8");
355 if (getLexer().isNot(AsmToken::EndOfStatement))
356 return TokError("unexpected token in directive");
359 // FIXME: Err on %xmm* registers
360 getStreamer().EmitWin64EHSaveReg(Reg, Off);
364 // FIXME: This method is inherently x86-specific. It should really be in the
366 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
369 if (ParseSEHRegisterNumber(Reg))
371 if (getLexer().isNot(AsmToken::Comma))
372 return TokError("you must specify an offset on the stack");
375 SMLoc startLoc = getLexer().getLoc();
376 if (getParser().ParseAbsoluteExpression(Off))
379 if (getLexer().isNot(AsmToken::EndOfStatement))
380 return TokError("unexpected token in directive");
383 return Error(startLoc, "offset is not a multiple of 16");
386 // FIXME: Err on non-%xmm* registers
387 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
391 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
394 if (getLexer().is(AsmToken::At)) {
395 SMLoc startLoc = getLexer().getLoc();
397 if (!getParser().ParseIdentifier(CodeID)) {
398 if (CodeID != "code")
399 return Error(startLoc, "expected @code");
404 if (getLexer().isNot(AsmToken::EndOfStatement))
405 return TokError("unexpected token in directive");
408 getStreamer().EmitWin64EHPushFrame(Code);
412 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
414 getStreamer().EmitWin64EHEndProlog();
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();
424 if (getParser().ParseIdentifier(identifier))
425 return Error(startLoc, "expected @unwind or @except");
426 if (identifier == "unwind")
428 else if (identifier == "except")
431 return Error(startLoc, "expected @unwind or @except");
435 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
436 SMLoc startLoc = getLexer().getLoc();
437 if (getLexer().is(AsmToken::Percent)) {
438 const MCRegisterInfo &MRI = getContext().getRegisterInfo();
441 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
445 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
446 // violation so this validation code is disabled.
448 // Check that this is a non-volatile register.
449 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
451 for (i = 0; NVRegs[i] != 0; ++i)
452 if (NVRegs[i] == LLVMRegNo)
455 return Error(startLoc, "expected non-volatile register");
458 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
460 return Error(startLoc,"register can't be represented in SEH unwind info");
465 if (getParser().ParseAbsoluteExpression(n))
468 return Error(startLoc, "register number is too high");
477 MCAsmParserExtension *createCOFFAsmParser() {
478 return new COFFAsmParser;