blob: 540df377bbd2e5df33deda0fd694b9db95bc18c3 [file] [log] [blame]
Michael J. Spencer7d490042010-10-09 11:01:07 +00001//===- 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/MCSectionCOFF.h"
16#include "llvm/MC/MCStreamer.h"
Charles Davisfbc539f2011-05-22 21:12:15 +000017#include "llvm/MC/MCExpr.h"
Charles Davis3b32d022011-05-24 20:06:30 +000018#include "llvm/Target/TargetAsmInfo.h"
19#include "llvm/Target/TargetAsmParser.h"
Michael J. Spencer7d490042010-10-09 11:01:07 +000020#include "llvm/Support/COFF.h"
21using namespace llvm;
22
23namespace {
24
25class 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");
Charles Davisfbc539f2011-05-22 21:12:15 +000047
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");
Michael J. Spencer7d490042010-10-09 11:01:07 +000075 }
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
Charles Davisfbc539f2011-05-22 21:12:15 +0000104 // 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);
Charles Davis3b32d022011-05-24 20:06:30 +0000111 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);
Charles Davisfbc539f2011-05-22 21:12:15 +0000117 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
118
119 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
Charles Davis3b32d022011-05-24 20:06:30 +0000120 bool ParseSEHRegisterNumber(unsigned &RegNo);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000121public:
122 COFFAsmParser() {}
123};
124
125} // end annonomous namespace.
126
127bool 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
140bool 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
154bool 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
167bool 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
180bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
181 Lex();
182 getStreamer().EndCOFFSymbolDef();
183 return false;
184}
185
Charles Davisfbc539f2011-05-22 21:12:15 +0000186bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000187 StringRef SymbolID;
188 if (getParser().ParseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000189 return true;
190
Charles Davisfbc539f2011-05-22 21:12:15 +0000191 if (getLexer().isNot(AsmToken::EndOfStatement))
192 return TokError("unexpected token in directive");
193
Charles Davis30921322011-05-25 01:33:42 +0000194 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
195
Charles Davisfbc539f2011-05-22 21:12:15 +0000196 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000197 getStreamer().EmitWin64EHStartProc(Symbol);
Charles Davisfbc539f2011-05-22 21:12:15 +0000198 return false;
199}
200
201bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
202 Lex();
203 getStreamer().EmitWin64EHEndProc();
204 return false;
205}
206
207bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
208 Lex();
209 getStreamer().EmitWin64EHStartChained();
210 return false;
211}
212
213bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
214 Lex();
215 getStreamer().EmitWin64EHEndChained();
216 return false;
217}
218
219bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000220 StringRef SymbolID;
221 if (getParser().ParseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000222 return true;
223
Charles Davis30921322011-05-25 01:33:42 +0000224 if (getLexer().isNot(AsmToken::Comma))
225 return TokError("you must specify one or both of @unwind or @except");
226 Lex();
Charles Davisfbc539f2011-05-22 21:12:15 +0000227 bool unwind = false, except = false;
Charles Davis30921322011-05-25 01:33:42 +0000228 if (ParseAtUnwindOrAtExcept(unwind, except))
229 return true;
Charles Davisfbc539f2011-05-22 21:12:15 +0000230 if (getLexer().is(AsmToken::Comma)) {
231 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000232 if (ParseAtUnwindOrAtExcept(unwind, except))
Charles Davisfbc539f2011-05-22 21:12:15 +0000233 return true;
234 }
235 if (getLexer().isNot(AsmToken::EndOfStatement))
236 return TokError("unexpected token in directive");
237
Charles Davis30921322011-05-25 01:33:42 +0000238 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
239
Charles Davisfbc539f2011-05-22 21:12:15 +0000240 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000241 getStreamer().EmitWin64EHHandler(handler, unwind, except);
Charles Davisfbc539f2011-05-22 21:12:15 +0000242 return false;
243}
244
245bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
246 Lex();
247 getStreamer().EmitWin64EHHandlerData();
248 return false;
249}
250
251bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000252 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;
Charles Davisfbc539f2011-05-22 21:12:15 +0000262}
263
264bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000265 unsigned Reg;
266 int64_t Off;
267 if (ParseSEHRegisterNumber(Reg))
268 return true;
269 SMLoc startLoc = getLexer().getLoc();
270 if (getParser().ParseAbsoluteExpression(Off))
271 return true;
272
273 if (Off & 0x0F)
274 return Error(startLoc, "offset is not a multiple of 16");
275
276 if (getLexer().isNot(AsmToken::EndOfStatement))
277 return TokError("unexpected token in directive");
278
279 Lex();
280 getStreamer().EmitWin64EHSetFrame(Reg, Off);
281 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000282}
283
Charles Davis16e1b3f2011-05-23 16:43:09 +0000284bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
285 int64_t Size;
Charles Davis3b32d022011-05-24 20:06:30 +0000286 SMLoc startLoc = getLexer().getLoc();
Charles Davis16e1b3f2011-05-23 16:43:09 +0000287 if (getParser().ParseAbsoluteExpression(Size))
288 return true;
289
Charles Davis3b32d022011-05-24 20:06:30 +0000290 if (Size & 7)
291 return Error(startLoc, "size is not a multiple of 8");
292
Charles Davis16e1b3f2011-05-23 16:43:09 +0000293 if (getLexer().isNot(AsmToken::EndOfStatement))
294 return TokError("unexpected token in directive");
295
296 Lex();
297 getStreamer().EmitWin64EHAllocStack(Size);
298 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000299}
300
301bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000302 unsigned Reg;
303 int64_t Off;
304 if (ParseSEHRegisterNumber(Reg))
305 return true;
306 SMLoc startLoc = getLexer().getLoc();
307 if (getParser().ParseAbsoluteExpression(Off))
308 return true;
309
310 if (Off & 7)
311 return Error(startLoc, "size is not a multiple of 8");
312
313 if (getLexer().isNot(AsmToken::EndOfStatement))
314 return TokError("unexpected token in directive");
315
316 Lex();
317 // FIXME: Err on %xmm* registers
318 getStreamer().EmitWin64EHSaveReg(Reg, Off);
319 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000320}
321
Charles Davis3b32d022011-05-24 20:06:30 +0000322// FIXME: This method is inherently x86-specific. It should really be in the
323// x86 backend.
Charles Davisfbc539f2011-05-22 21:12:15 +0000324bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000325 unsigned Reg;
326 int64_t Off;
327 if (ParseSEHRegisterNumber(Reg))
328 return true;
329 SMLoc startLoc = getLexer().getLoc();
330 if (getParser().ParseAbsoluteExpression(Off))
331 return true;
332
333 if (getLexer().isNot(AsmToken::EndOfStatement))
334 return TokError("unexpected token in directive");
335
336 if (Off & 0x0F)
337 return Error(startLoc, "offset is not a multiple of 16");
338
339 Lex();
340 // FIXME: Err on non-%xmm* registers
341 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
342 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000343}
344
Charles Davis16e1b3f2011-05-23 16:43:09 +0000345bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
Charles Davis47268162011-05-25 04:08:15 +0000346 bool Code = false;
Charles Davis16e1b3f2011-05-23 16:43:09 +0000347 StringRef CodeID;
Charles Davis47268162011-05-25 04:08:15 +0000348 if (getLexer().is(AsmToken::At)) {
349 SMLoc startLoc = getLexer().getLoc();
350 Lex();
351 if (!getParser().ParseIdentifier(CodeID)) {
352 if (CodeID != "code")
353 return Error(startLoc, "expected @code");
354 Code = true;
355 }
Charles Davis16e1b3f2011-05-23 16:43:09 +0000356 }
357
358 if (getLexer().isNot(AsmToken::EndOfStatement))
359 return TokError("unexpected token in directive");
360
361 Lex();
362 getStreamer().EmitWin64EHPushFrame(Code);
363 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000364}
365
366bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
367 Lex();
368 getStreamer().EmitWin64EHEndProlog();
369 return false;
370}
371
372bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
373 StringRef identifier;
Charles Davis30921322011-05-25 01:33:42 +0000374 if (getLexer().isNot(AsmToken::At))
375 return TokError("a handler attribute must begin with '@'");
Charles Davisfbc539f2011-05-22 21:12:15 +0000376 SMLoc startLoc = getLexer().getLoc();
Charles Davis30921322011-05-25 01:33:42 +0000377 Lex();
378 if (getParser().ParseIdentifier(identifier))
Charles Davisfbc539f2011-05-22 21:12:15 +0000379 return Error(startLoc, "expected @unwind or @except");
Charles Davis30921322011-05-25 01:33:42 +0000380 if (identifier == "unwind")
Charles Davisfbc539f2011-05-22 21:12:15 +0000381 unwind = true;
Charles Davis30921322011-05-25 01:33:42 +0000382 else if (identifier == "except")
Charles Davisfbc539f2011-05-22 21:12:15 +0000383 except = true;
384 else
385 return Error(startLoc, "expected @unwind or @except");
386 return false;
387}
388
Charles Davis3b32d022011-05-24 20:06:30 +0000389bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
390 int64_t n;
391 SMLoc startLoc = getLexer().getLoc();
392 if (getParser().ParseAbsoluteExpression(n)) {
393 const TargetAsmInfo &asmInfo = getContext().getTargetAsmInfo();
394 SMLoc endLoc;
395 unsigned LLVMRegNo;
396 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
397 return Error(startLoc, "expected register or number");
398
399 // Check that this is a non-volatile register.
400 const unsigned *NVRegs = asmInfo.getCalleeSavedRegs();
401 unsigned i;
402 for (i = 0; NVRegs[i] != 0; ++i)
403 if (NVRegs[i] == LLVMRegNo)
404 break;
405 if (NVRegs[i] == 0)
406 return Error(startLoc, "expected non-volatile register");
407
408 int SEHRegNo = asmInfo.getSEHRegNum(LLVMRegNo);
409 if (SEHRegNo < 0)
410 return Error(startLoc,"register can't be represented in SEH unwind info");
411 RegNo = SEHRegNo;
412 }
413 else
414 RegNo = n;
415
416 if (RegNo > 15)
417 return Error(startLoc, "register number is too high");
418 return false;
419}
420
Michael J. Spencer7d490042010-10-09 11:01:07 +0000421namespace llvm {
422
423MCAsmParserExtension *createCOFFAsmParser() {
424 return new COFFAsmParser;
425}
426
427}