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