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/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/MCSectionCOFF.h"
16 #include "llvm/MC/MCStreamer.h"
17 #include "llvm/MC/MCExpr.h"
18 #include "llvm/Target/TargetAsmInfo.h"
19 #include "llvm/Target/TargetAsmParser.h"
20 #include "llvm/Support/COFF.h"
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>);
32 bool ParseSectionSwitch(StringRef Section,
33 unsigned Characteristics,
36 virtual void Initialize(MCAsmParser &Parser) {
37 // Call the base implementation.
38 MCAsmParserExtension::Initialize(Parser);
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");
48 // Win64 EH directives.
49 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
51 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
53 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
55 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
57 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
59 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
61 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
63 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
65 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
67 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
69 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
71 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
73 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
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());
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());
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());
99 bool ParseDirectiveDef(StringRef, SMLoc);
100 bool ParseDirectiveScl(StringRef, SMLoc);
101 bool ParseDirectiveType(StringRef, SMLoc);
102 bool ParseDirectiveEndef(StringRef, SMLoc);
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);
119 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
120 bool ParseSEHRegisterNumber(unsigned &RegNo);
125 } // end annonomous namespace.
127 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
128 unsigned Characteristics,
130 if (getLexer().isNot(AsmToken::EndOfStatement))
131 return TokError("unexpected token in section switching directive");
134 getStreamer().SwitchSection(getContext().getCOFFSection(
135 Section, Characteristics, Kind));
140 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
141 StringRef SymbolName;
143 if (getParser().ParseIdentifier(SymbolName))
144 return TokError("expected identifier in directive");
146 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
148 getStreamer().BeginCOFFSymbolDef(Sym);
154 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
155 int64_t SymbolStorageClass;
156 if (getParser().ParseAbsoluteExpression(SymbolStorageClass))
159 if (getLexer().isNot(AsmToken::EndOfStatement))
160 return TokError("unexpected token in directive");
163 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
167 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
169 if (getParser().ParseAbsoluteExpression(Type))
172 if (getLexer().isNot(AsmToken::EndOfStatement))
173 return TokError("unexpected token in directive");
176 getStreamer().EmitCOFFSymbolType(Type);
180 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
182 getStreamer().EndCOFFSymbolDef();
186 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
188 const MCSymbolRefExpr *funcExpr;
189 SMLoc startLoc = getLexer().getLoc();
190 if (getParser().ParseExpression(e))
193 if (!(funcExpr = dyn_cast<MCSymbolRefExpr>(e)))
194 return Error(startLoc, "expected symbol");
196 if (getLexer().isNot(AsmToken::EndOfStatement))
197 return TokError("unexpected token in directive");
200 getStreamer().EmitWin64EHStartProc(&funcExpr->getSymbol());
204 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
206 getStreamer().EmitWin64EHEndProc();
210 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
212 getStreamer().EmitWin64EHStartChained();
216 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
218 getStreamer().EmitWin64EHEndChained();
222 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
224 const MCSymbolRefExpr *funcExpr;
225 SMLoc startLoc = getLexer().getLoc();
226 if (getParser().ParseExpression(e))
229 if (!(funcExpr = dyn_cast<MCSymbolRefExpr>(e)))
230 return Error(startLoc, "expected symbol");
232 bool unwind = false, except = false;
233 startLoc = getLexer().getLoc();
234 if (!ParseAtUnwindOrAtExcept(unwind, except))
235 return Error(startLoc,"you must specify one or both of @unwind or @except");
236 if (getLexer().is(AsmToken::Comma)) {
238 if (!ParseAtUnwindOrAtExcept(unwind, except))
241 if (getLexer().isNot(AsmToken::EndOfStatement))
242 return TokError("unexpected token in directive");
245 getStreamer().EmitWin64EHHandler(&funcExpr->getSymbol(), unwind, except);
249 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
251 getStreamer().EmitWin64EHHandlerData();
255 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
257 if (ParseSEHRegisterNumber(Reg))
260 if (getLexer().isNot(AsmToken::EndOfStatement))
261 return TokError("unexpected token in directive");
264 getStreamer().EmitWin64EHPushReg(Reg);
268 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
271 if (ParseSEHRegisterNumber(Reg))
273 SMLoc startLoc = getLexer().getLoc();
274 if (getParser().ParseAbsoluteExpression(Off))
278 return Error(startLoc, "offset is not a multiple of 16");
280 if (getLexer().isNot(AsmToken::EndOfStatement))
281 return TokError("unexpected token in directive");
284 getStreamer().EmitWin64EHSetFrame(Reg, Off);
288 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
290 SMLoc startLoc = getLexer().getLoc();
291 if (getParser().ParseAbsoluteExpression(Size))
295 return Error(startLoc, "size is not a multiple of 8");
297 if (getLexer().isNot(AsmToken::EndOfStatement))
298 return TokError("unexpected token in directive");
301 getStreamer().EmitWin64EHAllocStack(Size);
305 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
308 if (ParseSEHRegisterNumber(Reg))
310 SMLoc startLoc = getLexer().getLoc();
311 if (getParser().ParseAbsoluteExpression(Off))
315 return Error(startLoc, "size is not a multiple of 8");
317 if (getLexer().isNot(AsmToken::EndOfStatement))
318 return TokError("unexpected token in directive");
321 // FIXME: Err on %xmm* registers
322 getStreamer().EmitWin64EHSaveReg(Reg, Off);
326 // FIXME: This method is inherently x86-specific. It should really be in the
328 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
331 if (ParseSEHRegisterNumber(Reg))
333 SMLoc startLoc = getLexer().getLoc();
334 if (getParser().ParseAbsoluteExpression(Off))
337 if (getLexer().isNot(AsmToken::EndOfStatement))
338 return TokError("unexpected token in directive");
341 return Error(startLoc, "offset is not a multiple of 16");
344 // FIXME: Err on non-%xmm* registers
345 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
349 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
352 SMLoc startLoc = getLexer().getLoc();
353 if (!getParser().ParseIdentifier(CodeID)) {
354 if (CodeID != "@code")
355 return Error(startLoc, "expected @code");
359 if (getLexer().isNot(AsmToken::EndOfStatement))
360 return TokError("unexpected token in directive");
363 getStreamer().EmitWin64EHPushFrame(Code);
367 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
369 getStreamer().EmitWin64EHEndProlog();
373 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
374 StringRef identifier;
375 SMLoc startLoc = getLexer().getLoc();
376 if (!getParser().ParseIdentifier(identifier))
377 return Error(startLoc, "expected @unwind or @except");
378 if (identifier == "@unwind")
380 else if (identifier == "@except")
383 return Error(startLoc, "expected @unwind or @except");
387 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
389 SMLoc startLoc = getLexer().getLoc();
390 if (getParser().ParseAbsoluteExpression(n)) {
391 const TargetAsmInfo &asmInfo = getContext().getTargetAsmInfo();
394 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
395 return Error(startLoc, "expected register or number");
397 // Check that this is a non-volatile register.
398 const unsigned *NVRegs = asmInfo.getCalleeSavedRegs();
400 for (i = 0; NVRegs[i] != 0; ++i)
401 if (NVRegs[i] == LLVMRegNo)
404 return Error(startLoc, "expected non-volatile register");
406 int SEHRegNo = asmInfo.getSEHRegNum(LLVMRegNo);
408 return Error(startLoc,"register can't be represented in SEH unwind info");
415 return Error(startLoc, "register number is too high");
421 MCAsmParserExtension *createCOFFAsmParser() {
422 return new COFFAsmParser;