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