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/MCObjectFileInfo.h"
17 #include "llvm/MC/MCParser/MCAsmLexer.h"
18 #include "llvm/MC/MCRegisterInfo.h"
19 #include "llvm/MC/MCSectionCOFF.h"
20 #include "llvm/MC/MCStreamer.h"
21 #include "llvm/MC/MCTargetAsmParser.h"
22 #include "llvm/Support/COFF.h"
23 using namespace llvm;
24 
25 namespace {
26 
27 class COFFAsmParser : public MCAsmParserExtension {
28   template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)29   void addDirectiveHandler(StringRef Directive) {
30     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
31         this, HandleDirective<COFFAsmParser, HandlerMethod>);
32     getParser().addDirectiveHandler(Directive, Handler);
33   }
34 
35   bool ParseSectionSwitch(StringRef Section,
36                           unsigned Characteristics,
37                           SectionKind Kind);
38 
39   bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
40                           SectionKind Kind, StringRef COMDATSymName,
41                           COFF::COMDATType Type);
42 
43   bool ParseSectionName(StringRef &SectionName);
44   bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
45 
Initialize(MCAsmParser & Parser)46   void Initialize(MCAsmParser &Parser) override {
47     // Call the base implementation.
48     MCAsmParserExtension::Initialize(Parser);
49 
50     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
51     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
52     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
53     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
54     addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
55     addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
56     addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
57     addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
58     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
59     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
60     addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
61 
62     // Win64 EH directives.
63     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
64                                                                    ".seh_proc");
65     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
66                                                                 ".seh_endproc");
67     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
68                                                            ".seh_startchained");
69     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
70                                                              ".seh_endchained");
71     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
72                                                                 ".seh_handler");
73     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
74                                                             ".seh_handlerdata");
75     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
76                                                                 ".seh_pushreg");
77     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
78                                                                ".seh_setframe");
79     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
80                                                              ".seh_stackalloc");
81     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
82                                                                 ".seh_savereg");
83     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
84                                                                 ".seh_savexmm");
85     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
86                                                               ".seh_pushframe");
87     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
88                                                             ".seh_endprologue");
89     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
90   }
91 
ParseSectionDirectiveText(StringRef,SMLoc)92   bool ParseSectionDirectiveText(StringRef, SMLoc) {
93     return ParseSectionSwitch(".text",
94                               COFF::IMAGE_SCN_CNT_CODE
95                             | COFF::IMAGE_SCN_MEM_EXECUTE
96                             | COFF::IMAGE_SCN_MEM_READ,
97                               SectionKind::getText());
98   }
ParseSectionDirectiveData(StringRef,SMLoc)99   bool ParseSectionDirectiveData(StringRef, SMLoc) {
100     return ParseSectionSwitch(".data",
101                               COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
102                             | COFF::IMAGE_SCN_MEM_READ
103                             | COFF::IMAGE_SCN_MEM_WRITE,
104                               SectionKind::getDataRel());
105   }
ParseSectionDirectiveBSS(StringRef,SMLoc)106   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
107     return ParseSectionSwitch(".bss",
108                               COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
109                             | COFF::IMAGE_SCN_MEM_READ
110                             | COFF::IMAGE_SCN_MEM_WRITE,
111                               SectionKind::getBSS());
112   }
113 
114   bool ParseDirectiveSection(StringRef, SMLoc);
115   bool ParseDirectiveDef(StringRef, SMLoc);
116   bool ParseDirectiveScl(StringRef, SMLoc);
117   bool ParseDirectiveType(StringRef, SMLoc);
118   bool ParseDirectiveEndef(StringRef, SMLoc);
119   bool ParseDirectiveSecRel32(StringRef, SMLoc);
120   bool ParseDirectiveSecIdx(StringRef, SMLoc);
121   bool parseCOMDATType(COFF::COMDATType &Type);
122   bool ParseDirectiveLinkOnce(StringRef, SMLoc);
123 
124   // Win64 EH directives.
125   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
126   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
127   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
128   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
129   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
130   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
131   bool ParseSEHDirectivePushReg(StringRef, SMLoc);
132   bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
133   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
134   bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
135   bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
136   bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
137   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
138 
139   bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
140   bool ParseSEHRegisterNumber(unsigned &RegNo);
141   bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
142 public:
COFFAsmParser()143   COFFAsmParser() {}
144 };
145 
146 } // end annonomous namespace.
147 
computeSectionKind(unsigned Flags)148 static SectionKind computeSectionKind(unsigned Flags) {
149   if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
150     return SectionKind::getText();
151   if (Flags & COFF::IMAGE_SCN_MEM_READ &&
152       (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
153     return SectionKind::getReadOnly();
154   return SectionKind::getDataRel();
155 }
156 
ParseSectionFlags(StringRef FlagsString,unsigned * Flags)157 bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
158   enum {
159     None      = 0,
160     Alloc     = 1 << 0,
161     Code      = 1 << 1,
162     Load      = 1 << 2,
163     InitData  = 1 << 3,
164     Shared    = 1 << 4,
165     NoLoad    = 1 << 5,
166     NoRead    = 1 << 6,
167     NoWrite  =  1 << 7
168   };
169 
170   bool ReadOnlyRemoved = false;
171   unsigned SecFlags = None;
172 
173   for (char FlagChar : FlagsString) {
174     switch (FlagChar) {
175     case 'a':
176       // Ignored.
177       break;
178 
179     case 'b': // bss section
180       SecFlags |= Alloc;
181       if (SecFlags & InitData)
182         return TokError("conflicting section flags 'b' and 'd'.");
183       SecFlags &= ~Load;
184       break;
185 
186     case 'd': // data section
187       SecFlags |= InitData;
188       if (SecFlags & Alloc)
189         return TokError("conflicting section flags 'b' and 'd'.");
190       SecFlags &= ~NoWrite;
191       if ((SecFlags & NoLoad) == 0)
192         SecFlags |= Load;
193       break;
194 
195     case 'n': // section is not loaded
196       SecFlags |= NoLoad;
197       SecFlags &= ~Load;
198       break;
199 
200     case 'r': // read-only
201       ReadOnlyRemoved = false;
202       SecFlags |= NoWrite;
203       if ((SecFlags & Code) == 0)
204         SecFlags |= InitData;
205       if ((SecFlags & NoLoad) == 0)
206         SecFlags |= Load;
207       break;
208 
209     case 's': // shared section
210       SecFlags |= Shared | InitData;
211       SecFlags &= ~NoWrite;
212       if ((SecFlags & NoLoad) == 0)
213         SecFlags |= Load;
214       break;
215 
216     case 'w': // writable
217       SecFlags &= ~NoWrite;
218       ReadOnlyRemoved = true;
219       break;
220 
221     case 'x': // executable section
222       SecFlags |= Code;
223       if ((SecFlags & NoLoad) == 0)
224         SecFlags |= Load;
225       if (!ReadOnlyRemoved)
226         SecFlags |= NoWrite;
227       break;
228 
229     case 'y': // not readable
230       SecFlags |= NoRead | NoWrite;
231       break;
232 
233     default:
234       return TokError("unknown flag");
235     }
236   }
237 
238   *Flags = 0;
239 
240   if (SecFlags == None)
241     SecFlags = InitData;
242 
243   if (SecFlags & Code)
244     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
245   if (SecFlags & InitData)
246     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
247   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
248     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
249   if (SecFlags & NoLoad)
250     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
251   if ((SecFlags & NoRead) == 0)
252     *Flags |= COFF::IMAGE_SCN_MEM_READ;
253   if ((SecFlags & NoWrite) == 0)
254     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
255   if (SecFlags & Shared)
256     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
257 
258   return false;
259 }
260 
261 /// ParseDirectiveSymbolAttribute
262 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
ParseDirectiveSymbolAttribute(StringRef Directive,SMLoc)263 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
264   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
265     .Case(".weak", MCSA_Weak)
266     .Default(MCSA_Invalid);
267   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
268   if (getLexer().isNot(AsmToken::EndOfStatement)) {
269     for (;;) {
270       StringRef Name;
271 
272       if (getParser().parseIdentifier(Name))
273         return TokError("expected identifier in directive");
274 
275       MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
276 
277       getStreamer().EmitSymbolAttribute(Sym, Attr);
278 
279       if (getLexer().is(AsmToken::EndOfStatement))
280         break;
281 
282       if (getLexer().isNot(AsmToken::Comma))
283         return TokError("unexpected token in directive");
284       Lex();
285     }
286   }
287 
288   Lex();
289   return false;
290 }
291 
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind)292 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
293                                        unsigned Characteristics,
294                                        SectionKind Kind) {
295   return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
296 }
297 
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind,StringRef COMDATSymName,COFF::COMDATType Type)298 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
299                                        unsigned Characteristics,
300                                        SectionKind Kind,
301                                        StringRef COMDATSymName,
302                                        COFF::COMDATType Type) {
303   if (getLexer().isNot(AsmToken::EndOfStatement))
304     return TokError("unexpected token in section switching directive");
305   Lex();
306 
307   getStreamer().SwitchSection(getContext().getCOFFSection(
308       Section, Characteristics, Kind, COMDATSymName, Type));
309 
310   return false;
311 }
312 
ParseSectionName(StringRef & SectionName)313 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
314   if (!getLexer().is(AsmToken::Identifier))
315     return true;
316 
317   SectionName = getTok().getIdentifier();
318   Lex();
319   return false;
320 }
321 
322 // .section name [, "flags"] [, identifier [ identifier ], identifier]
323 //
324 // Supported flags:
325 //   a: Ignored.
326 //   b: BSS section (uninitialized data)
327 //   d: data section (initialized data)
328 //   n: Discardable section
329 //   r: Readable section
330 //   s: Shared section
331 //   w: Writable section
332 //   x: Executable section
333 //   y: Not-readable section (clears 'r')
334 //
335 // Subsections are not supported.
ParseDirectiveSection(StringRef,SMLoc)336 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
337   StringRef SectionName;
338 
339   if (ParseSectionName(SectionName))
340     return TokError("expected identifier in directive");
341 
342   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
343                    COFF::IMAGE_SCN_MEM_READ |
344                    COFF::IMAGE_SCN_MEM_WRITE;
345 
346   if (getLexer().is(AsmToken::Comma)) {
347     Lex();
348 
349     if (getLexer().isNot(AsmToken::String))
350       return TokError("expected string in directive");
351 
352     StringRef FlagsStr = getTok().getStringContents();
353     Lex();
354 
355     if (ParseSectionFlags(FlagsStr, &Flags))
356       return true;
357   }
358 
359   COFF::COMDATType Type = (COFF::COMDATType)0;
360   StringRef COMDATSymName;
361   if (getLexer().is(AsmToken::Comma)) {
362     Type = COFF::IMAGE_COMDAT_SELECT_ANY;;
363     Lex();
364 
365     Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
366 
367     if (!getLexer().is(AsmToken::Identifier))
368       return TokError("expected comdat type such as 'discard' or 'largest' "
369                       "after protection bits");
370 
371     if (parseCOMDATType(Type))
372       return true;
373 
374     if (getLexer().isNot(AsmToken::Comma))
375       return TokError("expected comma in directive");
376     Lex();
377 
378     if (getParser().parseIdentifier(COMDATSymName))
379       return TokError("expected identifier in directive");
380   }
381 
382   if (getLexer().isNot(AsmToken::EndOfStatement))
383     return TokError("unexpected token in directive");
384 
385   SectionKind Kind = computeSectionKind(Flags);
386   if (Kind.isText()) {
387     const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
388     if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
389       Flags |= COFF::IMAGE_SCN_MEM_16BIT;
390   }
391   ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
392   return false;
393 }
394 
ParseDirectiveDef(StringRef,SMLoc)395 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
396   StringRef SymbolName;
397 
398   if (getParser().parseIdentifier(SymbolName))
399     return TokError("expected identifier in directive");
400 
401   MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
402 
403   getStreamer().BeginCOFFSymbolDef(Sym);
404 
405   Lex();
406   return false;
407 }
408 
ParseDirectiveScl(StringRef,SMLoc)409 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
410   int64_t SymbolStorageClass;
411   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
412     return true;
413 
414   if (getLexer().isNot(AsmToken::EndOfStatement))
415     return TokError("unexpected token in directive");
416 
417   Lex();
418   getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
419   return false;
420 }
421 
ParseDirectiveType(StringRef,SMLoc)422 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
423   int64_t Type;
424   if (getParser().parseAbsoluteExpression(Type))
425     return true;
426 
427   if (getLexer().isNot(AsmToken::EndOfStatement))
428     return TokError("unexpected token in directive");
429 
430   Lex();
431   getStreamer().EmitCOFFSymbolType(Type);
432   return false;
433 }
434 
ParseDirectiveEndef(StringRef,SMLoc)435 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
436   Lex();
437   getStreamer().EndCOFFSymbolDef();
438   return false;
439 }
440 
ParseDirectiveSecRel32(StringRef,SMLoc)441 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
442   StringRef SymbolID;
443   if (getParser().parseIdentifier(SymbolID))
444     return TokError("expected identifier in directive");
445 
446   if (getLexer().isNot(AsmToken::EndOfStatement))
447     return TokError("unexpected token in directive");
448 
449   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
450 
451   Lex();
452   getStreamer().EmitCOFFSecRel32(Symbol);
453   return false;
454 }
455 
ParseDirectiveSecIdx(StringRef,SMLoc)456 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
457   StringRef SymbolID;
458   if (getParser().parseIdentifier(SymbolID))
459     return TokError("expected identifier in directive");
460 
461   if (getLexer().isNot(AsmToken::EndOfStatement))
462     return TokError("unexpected token in directive");
463 
464   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
465 
466   Lex();
467   getStreamer().EmitCOFFSectionIndex(Symbol);
468   return false;
469 }
470 
471 /// ::= [ identifier ]
parseCOMDATType(COFF::COMDATType & Type)472 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
473   StringRef TypeId = getTok().getIdentifier();
474 
475   Type = StringSwitch<COFF::COMDATType>(TypeId)
476     .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
477     .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
478     .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
479     .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
480     .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
481     .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
482     .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
483     .Default((COFF::COMDATType)0);
484 
485   if (Type == 0)
486     return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
487 
488   Lex();
489 
490   return false;
491 }
492 
493 /// ParseDirectiveLinkOnce
494 ///  ::= .linkonce [ identifier ]
ParseDirectiveLinkOnce(StringRef,SMLoc Loc)495 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
496   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
497   if (getLexer().is(AsmToken::Identifier))
498     if (parseCOMDATType(Type))
499       return true;
500 
501   const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
502                                        getStreamer().getCurrentSection().first);
503 
504   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
505     return Error(Loc, "cannot make section associative with .linkonce");
506 
507   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
508     return Error(Loc, Twine("section '") + Current->getSectionName() +
509                                                        "' is already linkonce");
510 
511   Current->setSelection(Type);
512 
513   if (getLexer().isNot(AsmToken::EndOfStatement))
514     return TokError("unexpected token in directive");
515 
516   return false;
517 }
518 
ParseSEHDirectiveStartProc(StringRef,SMLoc)519 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
520   StringRef SymbolID;
521   if (getParser().parseIdentifier(SymbolID))
522     return true;
523 
524   if (getLexer().isNot(AsmToken::EndOfStatement))
525     return TokError("unexpected token in directive");
526 
527   MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
528 
529   Lex();
530   getStreamer().EmitWinCFIStartProc(Symbol);
531   return false;
532 }
533 
ParseSEHDirectiveEndProc(StringRef,SMLoc)534 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
535   Lex();
536   getStreamer().EmitWinCFIEndProc();
537   return false;
538 }
539 
ParseSEHDirectiveStartChained(StringRef,SMLoc)540 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
541   Lex();
542   getStreamer().EmitWinCFIStartChained();
543   return false;
544 }
545 
ParseSEHDirectiveEndChained(StringRef,SMLoc)546 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
547   Lex();
548   getStreamer().EmitWinCFIEndChained();
549   return false;
550 }
551 
ParseSEHDirectiveHandler(StringRef,SMLoc)552 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
553   StringRef SymbolID;
554   if (getParser().parseIdentifier(SymbolID))
555     return true;
556 
557   if (getLexer().isNot(AsmToken::Comma))
558     return TokError("you must specify one or both of @unwind or @except");
559   Lex();
560   bool unwind = false, except = false;
561   if (ParseAtUnwindOrAtExcept(unwind, except))
562     return true;
563   if (getLexer().is(AsmToken::Comma)) {
564     Lex();
565     if (ParseAtUnwindOrAtExcept(unwind, except))
566       return true;
567   }
568   if (getLexer().isNot(AsmToken::EndOfStatement))
569     return TokError("unexpected token in directive");
570 
571   MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
572 
573   Lex();
574   getStreamer().EmitWinEHHandler(handler, unwind, except);
575   return false;
576 }
577 
ParseSEHDirectiveHandlerData(StringRef,SMLoc)578 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
579   Lex();
580   getStreamer().EmitWinEHHandlerData();
581   return false;
582 }
583 
ParseSEHDirectivePushReg(StringRef,SMLoc L)584 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
585   unsigned Reg = 0;
586   if (ParseSEHRegisterNumber(Reg))
587     return true;
588 
589   if (getLexer().isNot(AsmToken::EndOfStatement))
590     return TokError("unexpected token in directive");
591 
592   Lex();
593   getStreamer().EmitWinCFIPushReg(Reg);
594   return false;
595 }
596 
ParseSEHDirectiveSetFrame(StringRef,SMLoc L)597 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
598   unsigned Reg = 0;
599   int64_t Off;
600   if (ParseSEHRegisterNumber(Reg))
601     return true;
602   if (getLexer().isNot(AsmToken::Comma))
603     return TokError("you must specify a stack pointer offset");
604 
605   Lex();
606   SMLoc startLoc = getLexer().getLoc();
607   if (getParser().parseAbsoluteExpression(Off))
608     return true;
609 
610   if (Off & 0x0F)
611     return Error(startLoc, "offset is not a multiple of 16");
612 
613   if (getLexer().isNot(AsmToken::EndOfStatement))
614     return TokError("unexpected token in directive");
615 
616   Lex();
617   getStreamer().EmitWinCFISetFrame(Reg, Off);
618   return false;
619 }
620 
ParseSEHDirectiveAllocStack(StringRef,SMLoc)621 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
622   int64_t Size;
623   SMLoc startLoc = getLexer().getLoc();
624   if (getParser().parseAbsoluteExpression(Size))
625     return true;
626 
627   if (Size & 7)
628     return Error(startLoc, "size is not a multiple of 8");
629 
630   if (getLexer().isNot(AsmToken::EndOfStatement))
631     return TokError("unexpected token in directive");
632 
633   Lex();
634   getStreamer().EmitWinCFIAllocStack(Size);
635   return false;
636 }
637 
ParseSEHDirectiveSaveReg(StringRef,SMLoc L)638 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
639   unsigned Reg = 0;
640   int64_t Off;
641   if (ParseSEHRegisterNumber(Reg))
642     return true;
643   if (getLexer().isNot(AsmToken::Comma))
644     return TokError("you must specify an offset on the stack");
645 
646   Lex();
647   SMLoc startLoc = getLexer().getLoc();
648   if (getParser().parseAbsoluteExpression(Off))
649     return true;
650 
651   if (Off & 7)
652     return Error(startLoc, "size is not a multiple of 8");
653 
654   if (getLexer().isNot(AsmToken::EndOfStatement))
655     return TokError("unexpected token in directive");
656 
657   Lex();
658   // FIXME: Err on %xmm* registers
659   getStreamer().EmitWinCFISaveReg(Reg, Off);
660   return false;
661 }
662 
663 // FIXME: This method is inherently x86-specific. It should really be in the
664 // x86 backend.
ParseSEHDirectiveSaveXMM(StringRef,SMLoc L)665 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
666   unsigned Reg = 0;
667   int64_t Off;
668   if (ParseSEHRegisterNumber(Reg))
669     return true;
670   if (getLexer().isNot(AsmToken::Comma))
671     return TokError("you must specify an offset on the stack");
672 
673   Lex();
674   SMLoc startLoc = getLexer().getLoc();
675   if (getParser().parseAbsoluteExpression(Off))
676     return true;
677 
678   if (getLexer().isNot(AsmToken::EndOfStatement))
679     return TokError("unexpected token in directive");
680 
681   if (Off & 0x0F)
682     return Error(startLoc, "offset is not a multiple of 16");
683 
684   Lex();
685   // FIXME: Err on non-%xmm* registers
686   getStreamer().EmitWinCFISaveXMM(Reg, Off);
687   return false;
688 }
689 
ParseSEHDirectivePushFrame(StringRef,SMLoc)690 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
691   bool Code = false;
692   StringRef CodeID;
693   if (getLexer().is(AsmToken::At)) {
694     SMLoc startLoc = getLexer().getLoc();
695     Lex();
696     if (!getParser().parseIdentifier(CodeID)) {
697       if (CodeID != "code")
698         return Error(startLoc, "expected @code");
699       Code = true;
700     }
701   }
702 
703   if (getLexer().isNot(AsmToken::EndOfStatement))
704     return TokError("unexpected token in directive");
705 
706   Lex();
707   getStreamer().EmitWinCFIPushFrame(Code);
708   return false;
709 }
710 
ParseSEHDirectiveEndProlog(StringRef,SMLoc)711 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
712   Lex();
713   getStreamer().EmitWinCFIEndProlog();
714   return false;
715 }
716 
ParseAtUnwindOrAtExcept(bool & unwind,bool & except)717 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
718   StringRef identifier;
719   if (getLexer().isNot(AsmToken::At))
720     return TokError("a handler attribute must begin with '@'");
721   SMLoc startLoc = getLexer().getLoc();
722   Lex();
723   if (getParser().parseIdentifier(identifier))
724     return Error(startLoc, "expected @unwind or @except");
725   if (identifier == "unwind")
726     unwind = true;
727   else if (identifier == "except")
728     except = true;
729   else
730     return Error(startLoc, "expected @unwind or @except");
731   return false;
732 }
733 
ParseSEHRegisterNumber(unsigned & RegNo)734 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
735   SMLoc startLoc = getLexer().getLoc();
736   if (getLexer().is(AsmToken::Percent)) {
737     const MCRegisterInfo *MRI = getContext().getRegisterInfo();
738     SMLoc endLoc;
739     unsigned LLVMRegNo;
740     if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
741       return true;
742 
743 #if 0
744     // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
745     // violation so this validation code is disabled.
746 
747     // Check that this is a non-volatile register.
748     const unsigned *NVRegs = TAI.getCalleeSavedRegs();
749     unsigned i;
750     for (i = 0; NVRegs[i] != 0; ++i)
751       if (NVRegs[i] == LLVMRegNo)
752         break;
753     if (NVRegs[i] == 0)
754       return Error(startLoc, "expected non-volatile register");
755 #endif
756 
757     int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
758     if (SEHRegNo < 0)
759       return Error(startLoc,"register can't be represented in SEH unwind info");
760     RegNo = SEHRegNo;
761   }
762   else {
763     int64_t n;
764     if (getParser().parseAbsoluteExpression(n))
765       return true;
766     if (n > 15)
767       return Error(startLoc, "register number is too high");
768     RegNo = n;
769   }
770 
771   return false;
772 }
773 
774 namespace llvm {
775 
createCOFFAsmParser()776 MCAsmParserExtension *createCOFFAsmParser() {
777   return new COFFAsmParser;
778 }
779 
780 }
781