1 //===- 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/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"
22 using namespace llvm;
23
24 namespace {
25
26 class COFFAsmParser : public MCAsmParserExtension {
27 template<bool (COFFAsmParser::*Handler)(StringRef, SMLoc)>
AddDirectiveHandler(StringRef Directive)28 void AddDirectiveHandler(StringRef Directive) {
29 getParser().AddDirectiveHandler(this, Directive,
30 HandleDirective<COFFAsmParser, Handler>);
31 }
32
33 bool ParseSectionSwitch(StringRef Section,
34 unsigned Characteristics,
35 SectionKind Kind);
36
Initialize(MCAsmParser & Parser)37 virtual void Initialize(MCAsmParser &Parser) {
38 // Call the base implementation.
39 MCAsmParserExtension::Initialize(Parser);
40
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
49 // Win64 EH directives.
50 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
51 ".seh_proc");
52 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
53 ".seh_endproc");
54 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
55 ".seh_startchained");
56 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
57 ".seh_endchained");
58 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
59 ".seh_handler");
60 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
61 ".seh_handlerdata");
62 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
63 ".seh_pushreg");
64 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
65 ".seh_setframe");
66 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
67 ".seh_stackalloc");
68 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
69 ".seh_savereg");
70 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
71 ".seh_savexmm");
72 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
73 ".seh_pushframe");
74 AddDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
75 ".seh_endprologue");
76 AddDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
77 }
78
ParseSectionDirectiveText(StringRef,SMLoc)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());
85 }
ParseSectionDirectiveData(StringRef,SMLoc)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());
92 }
ParseSectionDirectiveBSS(StringRef,SMLoc)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());
99 }
100
101 bool ParseDirectiveDef(StringRef, SMLoc);
102 bool ParseDirectiveScl(StringRef, SMLoc);
103 bool ParseDirectiveType(StringRef, SMLoc);
104 bool ParseDirectiveEndef(StringRef, SMLoc);
105
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);
120
121 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
122 bool ParseSEHRegisterNumber(unsigned &RegNo);
123 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
124 public:
COFFAsmParser()125 COFFAsmParser() {}
126 };
127
128 } // end annonomous namespace.
129
130 /// ParseDirectiveSymbolAttribute
131 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
ParseDirectiveSymbolAttribute(StringRef Directive,SMLoc)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)) {
138 for (;;) {
139 StringRef Name;
140
141 if (getParser().ParseIdentifier(Name))
142 return TokError("expected identifier in directive");
143
144 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
145
146 getStreamer().EmitSymbolAttribute(Sym, Attr);
147
148 if (getLexer().is(AsmToken::EndOfStatement))
149 break;
150
151 if (getLexer().isNot(AsmToken::Comma))
152 return TokError("unexpected token in directive");
153 Lex();
154 }
155 }
156
157 Lex();
158 return false;
159 }
160
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind)161 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
162 unsigned Characteristics,
163 SectionKind Kind) {
164 if (getLexer().isNot(AsmToken::EndOfStatement))
165 return TokError("unexpected token in section switching directive");
166 Lex();
167
168 getStreamer().SwitchSection(getContext().getCOFFSection(
169 Section, Characteristics, Kind));
170
171 return false;
172 }
173
ParseDirectiveDef(StringRef,SMLoc)174 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
175 StringRef SymbolName;
176
177 if (getParser().ParseIdentifier(SymbolName))
178 return TokError("expected identifier in directive");
179
180 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
181
182 getStreamer().BeginCOFFSymbolDef(Sym);
183
184 Lex();
185 return false;
186 }
187
ParseDirectiveScl(StringRef,SMLoc)188 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
189 int64_t SymbolStorageClass;
190 if (getParser().ParseAbsoluteExpression(SymbolStorageClass))
191 return true;
192
193 if (getLexer().isNot(AsmToken::EndOfStatement))
194 return TokError("unexpected token in directive");
195
196 Lex();
197 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
198 return false;
199 }
200
ParseDirectiveType(StringRef,SMLoc)201 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
202 int64_t Type;
203 if (getParser().ParseAbsoluteExpression(Type))
204 return true;
205
206 if (getLexer().isNot(AsmToken::EndOfStatement))
207 return TokError("unexpected token in directive");
208
209 Lex();
210 getStreamer().EmitCOFFSymbolType(Type);
211 return false;
212 }
213
ParseDirectiveEndef(StringRef,SMLoc)214 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
215 Lex();
216 getStreamer().EndCOFFSymbolDef();
217 return false;
218 }
219
ParseSEHDirectiveStartProc(StringRef,SMLoc)220 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
221 StringRef SymbolID;
222 if (getParser().ParseIdentifier(SymbolID))
223 return true;
224
225 if (getLexer().isNot(AsmToken::EndOfStatement))
226 return TokError("unexpected token in directive");
227
228 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
229
230 Lex();
231 getStreamer().EmitWin64EHStartProc(Symbol);
232 return false;
233 }
234
ParseSEHDirectiveEndProc(StringRef,SMLoc)235 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
236 Lex();
237 getStreamer().EmitWin64EHEndProc();
238 return false;
239 }
240
ParseSEHDirectiveStartChained(StringRef,SMLoc)241 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
242 Lex();
243 getStreamer().EmitWin64EHStartChained();
244 return false;
245 }
246
ParseSEHDirectiveEndChained(StringRef,SMLoc)247 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
248 Lex();
249 getStreamer().EmitWin64EHEndChained();
250 return false;
251 }
252
ParseSEHDirectiveHandler(StringRef,SMLoc)253 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
254 StringRef SymbolID;
255 if (getParser().ParseIdentifier(SymbolID))
256 return true;
257
258 if (getLexer().isNot(AsmToken::Comma))
259 return TokError("you must specify one or both of @unwind or @except");
260 Lex();
261 bool unwind = false, except = false;
262 if (ParseAtUnwindOrAtExcept(unwind, except))
263 return true;
264 if (getLexer().is(AsmToken::Comma)) {
265 Lex();
266 if (ParseAtUnwindOrAtExcept(unwind, except))
267 return true;
268 }
269 if (getLexer().isNot(AsmToken::EndOfStatement))
270 return TokError("unexpected token in directive");
271
272 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
273
274 Lex();
275 getStreamer().EmitWin64EHHandler(handler, unwind, except);
276 return false;
277 }
278
ParseSEHDirectiveHandlerData(StringRef,SMLoc)279 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
280 Lex();
281 getStreamer().EmitWin64EHHandlerData();
282 return false;
283 }
284
ParseSEHDirectivePushReg(StringRef,SMLoc L)285 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
286 unsigned Reg;
287 if (ParseSEHRegisterNumber(Reg))
288 return true;
289
290 if (getLexer().isNot(AsmToken::EndOfStatement))
291 return TokError("unexpected token in directive");
292
293 Lex();
294 getStreamer().EmitWin64EHPushReg(Reg);
295 return false;
296 }
297
ParseSEHDirectiveSetFrame(StringRef,SMLoc L)298 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
299 unsigned Reg;
300 int64_t Off;
301 if (ParseSEHRegisterNumber(Reg))
302 return true;
303 if (getLexer().isNot(AsmToken::Comma))
304 return TokError("you must specify a stack pointer offset");
305
306 Lex();
307 SMLoc startLoc = getLexer().getLoc();
308 if (getParser().ParseAbsoluteExpression(Off))
309 return true;
310
311 if (Off & 0x0F)
312 return Error(startLoc, "offset is not a multiple of 16");
313
314 if (getLexer().isNot(AsmToken::EndOfStatement))
315 return TokError("unexpected token in directive");
316
317 Lex();
318 getStreamer().EmitWin64EHSetFrame(Reg, Off);
319 return false;
320 }
321
ParseSEHDirectiveAllocStack(StringRef,SMLoc)322 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
323 int64_t Size;
324 SMLoc startLoc = getLexer().getLoc();
325 if (getParser().ParseAbsoluteExpression(Size))
326 return true;
327
328 if (Size & 7)
329 return Error(startLoc, "size is not a multiple of 8");
330
331 if (getLexer().isNot(AsmToken::EndOfStatement))
332 return TokError("unexpected token in directive");
333
334 Lex();
335 getStreamer().EmitWin64EHAllocStack(Size);
336 return false;
337 }
338
ParseSEHDirectiveSaveReg(StringRef,SMLoc L)339 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
340 unsigned Reg;
341 int64_t Off;
342 if (ParseSEHRegisterNumber(Reg))
343 return true;
344 if (getLexer().isNot(AsmToken::Comma))
345 return TokError("you must specify an offset on the stack");
346
347 Lex();
348 SMLoc startLoc = getLexer().getLoc();
349 if (getParser().ParseAbsoluteExpression(Off))
350 return true;
351
352 if (Off & 7)
353 return Error(startLoc, "size is not a multiple of 8");
354
355 if (getLexer().isNot(AsmToken::EndOfStatement))
356 return TokError("unexpected token in directive");
357
358 Lex();
359 // FIXME: Err on %xmm* registers
360 getStreamer().EmitWin64EHSaveReg(Reg, Off);
361 return false;
362 }
363
364 // FIXME: This method is inherently x86-specific. It should really be in the
365 // x86 backend.
ParseSEHDirectiveSaveXMM(StringRef,SMLoc L)366 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
367 unsigned Reg;
368 int64_t Off;
369 if (ParseSEHRegisterNumber(Reg))
370 return true;
371 if (getLexer().isNot(AsmToken::Comma))
372 return TokError("you must specify an offset on the stack");
373
374 Lex();
375 SMLoc startLoc = getLexer().getLoc();
376 if (getParser().ParseAbsoluteExpression(Off))
377 return true;
378
379 if (getLexer().isNot(AsmToken::EndOfStatement))
380 return TokError("unexpected token in directive");
381
382 if (Off & 0x0F)
383 return Error(startLoc, "offset is not a multiple of 16");
384
385 Lex();
386 // FIXME: Err on non-%xmm* registers
387 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
388 return false;
389 }
390
ParseSEHDirectivePushFrame(StringRef,SMLoc)391 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
392 bool Code = false;
393 StringRef CodeID;
394 if (getLexer().is(AsmToken::At)) {
395 SMLoc startLoc = getLexer().getLoc();
396 Lex();
397 if (!getParser().ParseIdentifier(CodeID)) {
398 if (CodeID != "code")
399 return Error(startLoc, "expected @code");
400 Code = true;
401 }
402 }
403
404 if (getLexer().isNot(AsmToken::EndOfStatement))
405 return TokError("unexpected token in directive");
406
407 Lex();
408 getStreamer().EmitWin64EHPushFrame(Code);
409 return false;
410 }
411
ParseSEHDirectiveEndProlog(StringRef,SMLoc)412 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
413 Lex();
414 getStreamer().EmitWin64EHEndProlog();
415 return false;
416 }
417
ParseAtUnwindOrAtExcept(bool & unwind,bool & except)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();
423 Lex();
424 if (getParser().ParseIdentifier(identifier))
425 return Error(startLoc, "expected @unwind or @except");
426 if (identifier == "unwind")
427 unwind = true;
428 else if (identifier == "except")
429 except = true;
430 else
431 return Error(startLoc, "expected @unwind or @except");
432 return false;
433 }
434
ParseSEHRegisterNumber(unsigned & RegNo)435 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
436 SMLoc startLoc = getLexer().getLoc();
437 if (getLexer().is(AsmToken::Percent)) {
438 const MCRegisterInfo &MRI = getContext().getRegisterInfo();
439 SMLoc endLoc;
440 unsigned LLVMRegNo;
441 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
442 return true;
443
444 #if 0
445 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
446 // violation so this validation code is disabled.
447
448 // Check that this is a non-volatile register.
449 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
450 unsigned i;
451 for (i = 0; NVRegs[i] != 0; ++i)
452 if (NVRegs[i] == LLVMRegNo)
453 break;
454 if (NVRegs[i] == 0)
455 return Error(startLoc, "expected non-volatile register");
456 #endif
457
458 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
459 if (SEHRegNo < 0)
460 return Error(startLoc,"register can't be represented in SEH unwind info");
461 RegNo = SEHRegNo;
462 }
463 else {
464 int64_t n;
465 if (getParser().ParseAbsoluteExpression(n))
466 return true;
467 if (n > 15)
468 return Error(startLoc, "register number is too high");
469 RegNo = n;
470 }
471
472 return false;
473 }
474
475 namespace llvm {
476
createCOFFAsmParser()477 MCAsmParserExtension *createCOFFAsmParser() {
478 return new COFFAsmParser;
479 }
480
481 }
482