Home | History | Annotate | Download | only in MCParser
      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/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/MCRegisterInfo.h"
     16 #include "llvm/MC/MCSectionCOFF.h"
     17 #include "llvm/MC/MCStreamer.h"
     18 #include "llvm/MC/MCExpr.h"
     19 #include "llvm/Target/TargetAsmParser.h"
     20 #include "llvm/Support/COFF.h"
     21 using namespace llvm;
     22 
     23 namespace {
     24 
     25 class 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");
     47 
     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");
     75   }
     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 
    104   // 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);
    111   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);
    117   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
    118 
    119   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
    120   bool ParseSEHRegisterNumber(unsigned &RegNo);
    121 public:
    122   COFFAsmParser() {}
    123 };
    124 
    125 } // end annonomous namespace.
    126 
    127 bool 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 
    140 bool 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 
    154 bool 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 
    167 bool 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 
    180 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
    181   Lex();
    182   getStreamer().EndCOFFSymbolDef();
    183   return false;
    184 }
    185 
    186 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
    187   StringRef SymbolID;
    188   if (getParser().ParseIdentifier(SymbolID))
    189     return true;
    190 
    191   if (getLexer().isNot(AsmToken::EndOfStatement))
    192     return TokError("unexpected token in directive");
    193 
    194   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
    195 
    196   Lex();
    197   getStreamer().EmitWin64EHStartProc(Symbol);
    198   return false;
    199 }
    200 
    201 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
    202   Lex();
    203   getStreamer().EmitWin64EHEndProc();
    204   return false;
    205 }
    206 
    207 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
    208   Lex();
    209   getStreamer().EmitWin64EHStartChained();
    210   return false;
    211 }
    212 
    213 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
    214   Lex();
    215   getStreamer().EmitWin64EHEndChained();
    216   return false;
    217 }
    218 
    219 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
    220   StringRef SymbolID;
    221   if (getParser().ParseIdentifier(SymbolID))
    222     return true;
    223 
    224   if (getLexer().isNot(AsmToken::Comma))
    225     return TokError("you must specify one or both of @unwind or @except");
    226   Lex();
    227   bool unwind = false, except = false;
    228   if (ParseAtUnwindOrAtExcept(unwind, except))
    229     return true;
    230   if (getLexer().is(AsmToken::Comma)) {
    231     Lex();
    232     if (ParseAtUnwindOrAtExcept(unwind, except))
    233       return true;
    234   }
    235   if (getLexer().isNot(AsmToken::EndOfStatement))
    236     return TokError("unexpected token in directive");
    237 
    238   MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
    239 
    240   Lex();
    241   getStreamer().EmitWin64EHHandler(handler, unwind, except);
    242   return false;
    243 }
    244 
    245 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
    246   Lex();
    247   getStreamer().EmitWin64EHHandlerData();
    248   return false;
    249 }
    250 
    251 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
    252   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;
    262 }
    263 
    264 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
    265   unsigned Reg;
    266   int64_t Off;
    267   if (ParseSEHRegisterNumber(Reg))
    268     return true;
    269   if (getLexer().isNot(AsmToken::Comma))
    270     return TokError("you must specify a stack pointer offset");
    271 
    272   Lex();
    273   SMLoc startLoc = getLexer().getLoc();
    274   if (getParser().ParseAbsoluteExpression(Off))
    275     return true;
    276 
    277   if (Off & 0x0F)
    278     return Error(startLoc, "offset is not a multiple of 16");
    279 
    280   if (getLexer().isNot(AsmToken::EndOfStatement))
    281     return TokError("unexpected token in directive");
    282 
    283   Lex();
    284   getStreamer().EmitWin64EHSetFrame(Reg, Off);
    285   return false;
    286 }
    287 
    288 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
    289   int64_t Size;
    290   SMLoc startLoc = getLexer().getLoc();
    291   if (getParser().ParseAbsoluteExpression(Size))
    292     return true;
    293 
    294   if (Size & 7)
    295     return Error(startLoc, "size is not a multiple of 8");
    296 
    297   if (getLexer().isNot(AsmToken::EndOfStatement))
    298     return TokError("unexpected token in directive");
    299 
    300   Lex();
    301   getStreamer().EmitWin64EHAllocStack(Size);
    302   return false;
    303 }
    304 
    305 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
    306   unsigned Reg;
    307   int64_t Off;
    308   if (ParseSEHRegisterNumber(Reg))
    309     return true;
    310   if (getLexer().isNot(AsmToken::Comma))
    311     return TokError("you must specify an offset on the stack");
    312 
    313   Lex();
    314   SMLoc startLoc = getLexer().getLoc();
    315   if (getParser().ParseAbsoluteExpression(Off))
    316     return true;
    317 
    318   if (Off & 7)
    319     return Error(startLoc, "size is not a multiple of 8");
    320 
    321   if (getLexer().isNot(AsmToken::EndOfStatement))
    322     return TokError("unexpected token in directive");
    323 
    324   Lex();
    325   // FIXME: Err on %xmm* registers
    326   getStreamer().EmitWin64EHSaveReg(Reg, Off);
    327   return false;
    328 }
    329 
    330 // FIXME: This method is inherently x86-specific. It should really be in the
    331 // x86 backend.
    332 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
    333   unsigned Reg;
    334   int64_t Off;
    335   if (ParseSEHRegisterNumber(Reg))
    336     return true;
    337   if (getLexer().isNot(AsmToken::Comma))
    338     return TokError("you must specify an offset on the stack");
    339 
    340   Lex();
    341   SMLoc startLoc = getLexer().getLoc();
    342   if (getParser().ParseAbsoluteExpression(Off))
    343     return true;
    344 
    345   if (getLexer().isNot(AsmToken::EndOfStatement))
    346     return TokError("unexpected token in directive");
    347 
    348   if (Off & 0x0F)
    349     return Error(startLoc, "offset is not a multiple of 16");
    350 
    351   Lex();
    352   // FIXME: Err on non-%xmm* registers
    353   getStreamer().EmitWin64EHSaveXMM(Reg, Off);
    354   return false;
    355 }
    356 
    357 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
    358   bool Code = false;
    359   StringRef CodeID;
    360   if (getLexer().is(AsmToken::At)) {
    361     SMLoc startLoc = getLexer().getLoc();
    362     Lex();
    363     if (!getParser().ParseIdentifier(CodeID)) {
    364       if (CodeID != "code")
    365         return Error(startLoc, "expected @code");
    366       Code = true;
    367     }
    368   }
    369 
    370   if (getLexer().isNot(AsmToken::EndOfStatement))
    371     return TokError("unexpected token in directive");
    372 
    373   Lex();
    374   getStreamer().EmitWin64EHPushFrame(Code);
    375   return false;
    376 }
    377 
    378 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
    379   Lex();
    380   getStreamer().EmitWin64EHEndProlog();
    381   return false;
    382 }
    383 
    384 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
    385   StringRef identifier;
    386   if (getLexer().isNot(AsmToken::At))
    387     return TokError("a handler attribute must begin with '@'");
    388   SMLoc startLoc = getLexer().getLoc();
    389   Lex();
    390   if (getParser().ParseIdentifier(identifier))
    391     return Error(startLoc, "expected @unwind or @except");
    392   if (identifier == "unwind")
    393     unwind = true;
    394   else if (identifier == "except")
    395     except = true;
    396   else
    397     return Error(startLoc, "expected @unwind or @except");
    398   return false;
    399 }
    400 
    401 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
    402   SMLoc startLoc = getLexer().getLoc();
    403   if (getLexer().is(AsmToken::Percent)) {
    404     const MCRegisterInfo &MRI = getContext().getRegisterInfo();
    405     SMLoc endLoc;
    406     unsigned LLVMRegNo;
    407     if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
    408       return true;
    409 
    410 #if 0
    411     // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
    412     // violation so this validation code is disabled.
    413 
    414     // Check that this is a non-volatile register.
    415     const unsigned *NVRegs = TAI.getCalleeSavedRegs();
    416     unsigned i;
    417     for (i = 0; NVRegs[i] != 0; ++i)
    418       if (NVRegs[i] == LLVMRegNo)
    419         break;
    420     if (NVRegs[i] == 0)
    421       return Error(startLoc, "expected non-volatile register");
    422 #endif
    423 
    424     int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
    425     if (SEHRegNo < 0)
    426       return Error(startLoc,"register can't be represented in SEH unwind info");
    427     RegNo = SEHRegNo;
    428   }
    429   else {
    430     int64_t n;
    431     if (getParser().ParseAbsoluteExpression(n))
    432       return true;
    433     if (n > 15)
    434       return Error(startLoc, "register number is too high");
    435     RegNo = n;
    436   }
    437 
    438   return false;
    439 }
    440 
    441 namespace llvm {
    442 
    443 MCAsmParserExtension *createCOFFAsmParser() {
    444   return new COFFAsmParser;
    445 }
    446 
    447 }
    448