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"
22using namespace llvm;
23
24namespace {
25
26class 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);
124public:
125  COFFAsmParser() {}
126};
127
128} // end annonomous namespace.
129
130/// ParseDirectiveSymbolAttribute
131///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
132bool 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
161bool 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
174bool 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
188bool 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
201bool 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
214bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
215  Lex();
216  getStreamer().EndCOFFSymbolDef();
217  return false;
218}
219
220bool 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
235bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
236  Lex();
237  getStreamer().EmitWin64EHEndProc();
238  return false;
239}
240
241bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
242  Lex();
243  getStreamer().EmitWin64EHStartChained();
244  return false;
245}
246
247bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
248  Lex();
249  getStreamer().EmitWin64EHEndChained();
250  return false;
251}
252
253bool 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
279bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
280  Lex();
281  getStreamer().EmitWin64EHHandlerData();
282  return false;
283}
284
285bool 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
298bool 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
322bool 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
339bool 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.
366bool 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
391bool 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
412bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
413  Lex();
414  getStreamer().EmitWin64EHEndProlog();
415  return false;
416}
417
418bool 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
435bool 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
475namespace llvm {
476
477MCAsmParserExtension *createCOFFAsmParser() {
478  return new COFFAsmParser;
479}
480
481}
482