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/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     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);
    126 public:
    127   COFFAsmParser() {}
    128 };
    129 
    130 } // end annonomous namespace.
    131 
    132 /// ParseDirectiveSymbolAttribute
    133 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
    134 bool 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 
    163 bool 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 
    176 bool 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 
    190 bool 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 
    203 bool 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 
    216 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
    217   Lex();
    218   getStreamer().EndCOFFSymbolDef();
    219   return false;
    220 }
    221 
    222 bool 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 
    237 bool 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 
    252 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
    253   Lex();
    254   getStreamer().EmitWin64EHEndProc();
    255   return false;
    256 }
    257 
    258 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
    259   Lex();
    260   getStreamer().EmitWin64EHStartChained();
    261   return false;
    262 }
    263 
    264 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
    265   Lex();
    266   getStreamer().EmitWin64EHEndChained();
    267   return false;
    268 }
    269 
    270 bool 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 
    296 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
    297   Lex();
    298   getStreamer().EmitWin64EHHandlerData();
    299   return false;
    300 }
    301 
    302 bool 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 
    315 bool 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 
    339 bool 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 
    356 bool 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.
    383 bool 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 
    408 bool 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 
    429 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
    430   Lex();
    431   getStreamer().EmitWin64EHEndProlog();
    432   return false;
    433 }
    434 
    435 bool 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 
    452 bool 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 
    492 namespace llvm {
    493 
    494 MCAsmParserExtension *createCOFFAsmParser() {
    495   return new COFFAsmParser;
    496 }
    497 
    498 }
    499