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