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