]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / llvm / lib / MC / MCParser / COFFAsmParser.cpp
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)>
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
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
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   }
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   }
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:
125   COFFAsmParser() {}
126 };
127
128 } // end annonomous namespace.
129
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)) {
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
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
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
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
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
214 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
215   Lex();
216   getStreamer().EndCOFFSymbolDef();
217   return false;
218 }
219
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
235 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
236   Lex();
237   getStreamer().EmitWin64EHEndProc();
238   return false;
239 }
240
241 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
242   Lex();
243   getStreamer().EmitWin64EHStartChained();
244   return false;
245 }
246
247 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
248   Lex();
249   getStreamer().EmitWin64EHEndChained();
250   return false;
251 }
252
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
279 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
280   Lex();
281   getStreamer().EmitWin64EHHandlerData();
282   return false;
283 }
284
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
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
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
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.
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
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
412 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
413   Lex();
414   getStreamer().EmitWin64EHEndProlog();
415   return false;
416 }
417
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
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
477 MCAsmParserExtension *createCOFFAsmParser() {
478   return new COFFAsmParser;
479 }
480
481 }