]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/MC/MCParser/COFFAsmParser.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / MC / MCParser / COFFAsmParser.cpp
1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/StringSwitch.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCDirectives.h"
16 #include "llvm/MC/MCObjectFileInfo.h"
17 #include "llvm/MC/MCParser/MCAsmLexer.h"
18 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
19 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCSectionCOFF.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/SectionKind.h"
24 #include "llvm/Support/SMLoc.h"
25 #include <cassert>
26 #include <cstdint>
27 #include <limits>
28 #include <utility>
29
30 using namespace llvm;
31
32 namespace {
33
34 class COFFAsmParser : public MCAsmParserExtension {
35   template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
36   void addDirectiveHandler(StringRef Directive) {
37     MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
38         this, HandleDirective<COFFAsmParser, HandlerMethod>);
39     getParser().addDirectiveHandler(Directive, Handler);
40   }
41
42   bool ParseSectionSwitch(StringRef Section,
43                           unsigned Characteristics,
44                           SectionKind Kind);
45
46   bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47                           SectionKind Kind, StringRef COMDATSymName,
48                           COFF::COMDATType Type);
49
50   bool ParseSectionName(StringRef &SectionName);
51   bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
52                          unsigned *Flags);
53
54   void Initialize(MCAsmParser &Parser) override {
55     // Call the base implementation.
56     MCAsmParserExtension::Initialize(Parser);
57
58     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
59     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
60     addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
61     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
62     addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
63     addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
64     addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
65     addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
66     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
67     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
68     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
69     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
70     addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
71     addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
72     addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
73
74     // Win64 EH directives.
75     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
76                                                                    ".seh_proc");
77     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
78                                                                 ".seh_endproc");
79     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
80                                                            ".seh_startchained");
81     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
82                                                              ".seh_endchained");
83     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
84                                                                 ".seh_handler");
85     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
86                                                             ".seh_handlerdata");
87     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
88                                                              ".seh_stackalloc");
89     addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
90                                                             ".seh_endprologue");
91   }
92
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   }
100
101   bool ParseSectionDirectiveData(StringRef, SMLoc) {
102     return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
103                                            COFF::IMAGE_SCN_MEM_READ |
104                                            COFF::IMAGE_SCN_MEM_WRITE,
105                               SectionKind::getData());
106   }
107
108   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
109     return ParseSectionSwitch(".bss",
110                               COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
111                             | COFF::IMAGE_SCN_MEM_READ
112                             | COFF::IMAGE_SCN_MEM_WRITE,
113                               SectionKind::getBSS());
114   }
115
116   bool ParseDirectiveSection(StringRef, SMLoc);
117   bool ParseDirectiveDef(StringRef, SMLoc);
118   bool ParseDirectiveScl(StringRef, SMLoc);
119   bool ParseDirectiveType(StringRef, SMLoc);
120   bool ParseDirectiveEndef(StringRef, SMLoc);
121   bool ParseDirectiveSecRel32(StringRef, SMLoc);
122   bool ParseDirectiveSecIdx(StringRef, SMLoc);
123   bool ParseDirectiveSafeSEH(StringRef, SMLoc);
124   bool ParseDirectiveSymIdx(StringRef, SMLoc);
125   bool parseCOMDATType(COFF::COMDATType &Type);
126   bool ParseDirectiveLinkOnce(StringRef, SMLoc);
127   bool ParseDirectiveRVA(StringRef, SMLoc);
128
129   // Win64 EH directives.
130   bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
131   bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
132   bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
133   bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
134   bool ParseSEHDirectiveHandler(StringRef, SMLoc);
135   bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
136   bool ParseSEHDirectiveAllocStack(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
143 public:
144   COFFAsmParser() = default;
145 };
146
147 } // end anonymous namespace.
148
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
158 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
159                                       StringRef FlagsString, unsigned *Flags) {
160   enum {
161     None        = 0,
162     Alloc       = 1 << 0,
163     Code        = 1 << 1,
164     Load        = 1 << 2,
165     InitData    = 1 << 3,
166     Shared      = 1 << 4,
167     NoLoad      = 1 << 5,
168     NoRead      = 1 << 6,
169     NoWrite     = 1 << 7,
170     Discardable = 1 << 8,
171   };
172
173   bool ReadOnlyRemoved = false;
174   unsigned SecFlags = None;
175
176   for (char FlagChar : FlagsString) {
177     switch (FlagChar) {
178     case 'a':
179       // Ignored.
180       break;
181
182     case 'b': // bss section
183       SecFlags |= Alloc;
184       if (SecFlags & InitData)
185         return TokError("conflicting section flags 'b' and 'd'.");
186       SecFlags &= ~Load;
187       break;
188
189     case 'd': // data section
190       SecFlags |= InitData;
191       if (SecFlags & Alloc)
192         return TokError("conflicting section flags 'b' and 'd'.");
193       SecFlags &= ~NoWrite;
194       if ((SecFlags & NoLoad) == 0)
195         SecFlags |= Load;
196       break;
197
198     case 'n': // section is not loaded
199       SecFlags |= NoLoad;
200       SecFlags &= ~Load;
201       break;
202
203     case 'D': // discardable
204       SecFlags |= Discardable;
205       break;
206
207     case 'r': // read-only
208       ReadOnlyRemoved = false;
209       SecFlags |= NoWrite;
210       if ((SecFlags & Code) == 0)
211         SecFlags |= InitData;
212       if ((SecFlags & NoLoad) == 0)
213         SecFlags |= Load;
214       break;
215
216     case 's': // shared section
217       SecFlags |= Shared | InitData;
218       SecFlags &= ~NoWrite;
219       if ((SecFlags & NoLoad) == 0)
220         SecFlags |= Load;
221       break;
222
223     case 'w': // writable
224       SecFlags &= ~NoWrite;
225       ReadOnlyRemoved = true;
226       break;
227
228     case 'x': // executable section
229       SecFlags |= Code;
230       if ((SecFlags & NoLoad) == 0)
231         SecFlags |= Load;
232       if (!ReadOnlyRemoved)
233         SecFlags |= NoWrite;
234       break;
235
236     case 'y': // not readable
237       SecFlags |= NoRead | NoWrite;
238       break;
239
240     default:
241       return TokError("unknown flag");
242     }
243   }
244
245   *Flags = 0;
246
247   if (SecFlags == None)
248     SecFlags = InitData;
249
250   if (SecFlags & Code)
251     *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
252   if (SecFlags & InitData)
253     *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
254   if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
255     *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
256   if (SecFlags & NoLoad)
257     *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
258   if ((SecFlags & Discardable) ||
259       MCSectionCOFF::isImplicitlyDiscardable(SectionName))
260     *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
261   if ((SecFlags & NoRead) == 0)
262     *Flags |= COFF::IMAGE_SCN_MEM_READ;
263   if ((SecFlags & NoWrite) == 0)
264     *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
265   if (SecFlags & Shared)
266     *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
267
268   return false;
269 }
270
271 /// ParseDirectiveSymbolAttribute
272 ///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
273 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
274   MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
275     .Case(".weak", MCSA_Weak)
276     .Default(MCSA_Invalid);
277   assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
278   if (getLexer().isNot(AsmToken::EndOfStatement)) {
279     while (true) {
280       StringRef Name;
281
282       if (getParser().parseIdentifier(Name))
283         return TokError("expected identifier in directive");
284
285       MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
286
287       getStreamer().EmitSymbolAttribute(Sym, Attr);
288
289       if (getLexer().is(AsmToken::EndOfStatement))
290         break;
291
292       if (getLexer().isNot(AsmToken::Comma))
293         return TokError("unexpected token in directive");
294       Lex();
295     }
296   }
297
298   Lex();
299   return false;
300 }
301
302 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
303                                        unsigned Characteristics,
304                                        SectionKind Kind) {
305   return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
306 }
307
308 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
309                                        unsigned Characteristics,
310                                        SectionKind Kind,
311                                        StringRef COMDATSymName,
312                                        COFF::COMDATType Type) {
313   if (getLexer().isNot(AsmToken::EndOfStatement))
314     return TokError("unexpected token in section switching directive");
315   Lex();
316
317   getStreamer().SwitchSection(getContext().getCOFFSection(
318       Section, Characteristics, Kind, COMDATSymName, Type));
319
320   return false;
321 }
322
323 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
324   if (!getLexer().is(AsmToken::Identifier))
325     return true;
326
327   SectionName = getTok().getIdentifier();
328   Lex();
329   return false;
330 }
331
332 // .section name [, "flags"] [, identifier [ identifier ], identifier]
333 //
334 // Supported flags:
335 //   a: Ignored.
336 //   b: BSS section (uninitialized data)
337 //   d: data section (initialized data)
338 //   n: "noload" section (removed by linker)
339 //   D: Discardable section
340 //   r: Readable section
341 //   s: Shared section
342 //   w: Writable section
343 //   x: Executable section
344 //   y: Not-readable section (clears 'r')
345 //
346 // Subsections are not supported.
347 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
348   StringRef SectionName;
349
350   if (ParseSectionName(SectionName))
351     return TokError("expected identifier in directive");
352
353   unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
354                    COFF::IMAGE_SCN_MEM_READ |
355                    COFF::IMAGE_SCN_MEM_WRITE;
356
357   if (getLexer().is(AsmToken::Comma)) {
358     Lex();
359
360     if (getLexer().isNot(AsmToken::String))
361       return TokError("expected string in directive");
362
363     StringRef FlagsStr = getTok().getStringContents();
364     Lex();
365
366     if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
367       return true;
368   }
369
370   COFF::COMDATType Type = (COFF::COMDATType)0;
371   StringRef COMDATSymName;
372   if (getLexer().is(AsmToken::Comma)) {
373     Type = COFF::IMAGE_COMDAT_SELECT_ANY;
374     Lex();
375
376     Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
377
378     if (!getLexer().is(AsmToken::Identifier))
379       return TokError("expected comdat type such as 'discard' or 'largest' "
380                       "after protection bits");
381
382     if (parseCOMDATType(Type))
383       return true;
384
385     if (getLexer().isNot(AsmToken::Comma))
386       return TokError("expected comma in directive");
387     Lex();
388
389     if (getParser().parseIdentifier(COMDATSymName))
390       return TokError("expected identifier in directive");
391   }
392
393   if (getLexer().isNot(AsmToken::EndOfStatement))
394     return TokError("unexpected token in directive");
395
396   SectionKind Kind = computeSectionKind(Flags);
397   if (Kind.isText()) {
398     const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
399     if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
400       Flags |= COFF::IMAGE_SCN_MEM_16BIT;
401   }
402   ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
403   return false;
404 }
405
406 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
407   StringRef SymbolName;
408
409   if (getParser().parseIdentifier(SymbolName))
410     return TokError("expected identifier in directive");
411
412   MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
413
414   getStreamer().BeginCOFFSymbolDef(Sym);
415
416   Lex();
417   return false;
418 }
419
420 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
421   int64_t SymbolStorageClass;
422   if (getParser().parseAbsoluteExpression(SymbolStorageClass))
423     return true;
424
425   if (getLexer().isNot(AsmToken::EndOfStatement))
426     return TokError("unexpected token in directive");
427
428   Lex();
429   getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
430   return false;
431 }
432
433 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
434   int64_t Type;
435   if (getParser().parseAbsoluteExpression(Type))
436     return true;
437
438   if (getLexer().isNot(AsmToken::EndOfStatement))
439     return TokError("unexpected token in directive");
440
441   Lex();
442   getStreamer().EmitCOFFSymbolType(Type);
443   return false;
444 }
445
446 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
447   Lex();
448   getStreamer().EndCOFFSymbolDef();
449   return false;
450 }
451
452 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
453   StringRef SymbolID;
454   if (getParser().parseIdentifier(SymbolID))
455     return TokError("expected identifier in directive");
456
457   int64_t Offset = 0;
458   SMLoc OffsetLoc;
459   if (getLexer().is(AsmToken::Plus)) {
460     OffsetLoc = getLexer().getLoc();
461     if (getParser().parseAbsoluteExpression(Offset))
462       return true;
463   }
464
465   if (getLexer().isNot(AsmToken::EndOfStatement))
466     return TokError("unexpected token in directive");
467
468   if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
469     return Error(
470         OffsetLoc,
471         "invalid '.secrel32' directive offset, can't be less "
472         "than zero or greater than std::numeric_limits<uint32_t>::max()");
473
474   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
475
476   Lex();
477   getStreamer().EmitCOFFSecRel32(Symbol, Offset);
478   return false;
479 }
480
481 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
482   auto parseOp = [&]() -> bool {
483     StringRef SymbolID;
484     if (getParser().parseIdentifier(SymbolID))
485       return TokError("expected identifier in directive");
486
487     int64_t Offset = 0;
488     SMLoc OffsetLoc;
489     if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
490       OffsetLoc = getLexer().getLoc();
491       if (getParser().parseAbsoluteExpression(Offset))
492         return true;
493     }
494
495     if (Offset < std::numeric_limits<int32_t>::min() ||
496         Offset > std::numeric_limits<int32_t>::max())
497       return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
498                               "than -2147483648 or greater than "
499                               "2147483647");
500
501     MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
502
503     getStreamer().EmitCOFFImgRel32(Symbol, Offset);
504     return false;
505   };
506
507   if (getParser().parseMany(parseOp))
508     return addErrorSuffix(" in directive");
509   return false;
510 }
511
512 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
513   StringRef SymbolID;
514   if (getParser().parseIdentifier(SymbolID))
515     return TokError("expected identifier in directive");
516
517   if (getLexer().isNot(AsmToken::EndOfStatement))
518     return TokError("unexpected token in directive");
519
520   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
521
522   Lex();
523   getStreamer().EmitCOFFSafeSEH(Symbol);
524   return false;
525 }
526
527 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
528   StringRef SymbolID;
529   if (getParser().parseIdentifier(SymbolID))
530     return TokError("expected identifier in directive");
531
532   if (getLexer().isNot(AsmToken::EndOfStatement))
533     return TokError("unexpected token in directive");
534
535   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
536
537   Lex();
538   getStreamer().EmitCOFFSectionIndex(Symbol);
539   return false;
540 }
541
542 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
543   StringRef SymbolID;
544   if (getParser().parseIdentifier(SymbolID))
545     return TokError("expected identifier in directive");
546
547   if (getLexer().isNot(AsmToken::EndOfStatement))
548     return TokError("unexpected token in directive");
549
550   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
551
552   Lex();
553   getStreamer().EmitCOFFSymbolIndex(Symbol);
554   return false;
555 }
556
557 /// ::= [ identifier ]
558 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
559   StringRef TypeId = getTok().getIdentifier();
560
561   Type = StringSwitch<COFF::COMDATType>(TypeId)
562     .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
563     .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
564     .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
565     .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
566     .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
567     .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
568     .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
569     .Default((COFF::COMDATType)0);
570
571   if (Type == 0)
572     return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
573
574   Lex();
575
576   return false;
577 }
578
579 /// ParseDirectiveLinkOnce
580 ///  ::= .linkonce [ identifier ]
581 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
582   COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
583   if (getLexer().is(AsmToken::Identifier))
584     if (parseCOMDATType(Type))
585       return true;
586
587   const MCSectionCOFF *Current =
588       static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
589
590   if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
591     return Error(Loc, "cannot make section associative with .linkonce");
592
593   if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
594     return Error(Loc, Twine("section '") + Current->getSectionName() +
595                                                        "' is already linkonce");
596
597   Current->setSelection(Type);
598
599   if (getLexer().isNot(AsmToken::EndOfStatement))
600     return TokError("unexpected token in directive");
601
602   return false;
603 }
604
605 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
606   StringRef SymbolID;
607   if (getParser().parseIdentifier(SymbolID))
608     return true;
609
610   if (getLexer().isNot(AsmToken::EndOfStatement))
611     return TokError("unexpected token in directive");
612
613   MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
614
615   Lex();
616   getStreamer().EmitWinCFIStartProc(Symbol, Loc);
617   return false;
618 }
619
620 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
621   Lex();
622   getStreamer().EmitWinCFIEndProc(Loc);
623   return false;
624 }
625
626 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
627   Lex();
628   getStreamer().EmitWinCFIStartChained(Loc);
629   return false;
630 }
631
632 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
633   Lex();
634   getStreamer().EmitWinCFIEndChained(Loc);
635   return false;
636 }
637
638 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
639   StringRef SymbolID;
640   if (getParser().parseIdentifier(SymbolID))
641     return true;
642
643   if (getLexer().isNot(AsmToken::Comma))
644     return TokError("you must specify one or both of @unwind or @except");
645   Lex();
646   bool unwind = false, except = false;
647   if (ParseAtUnwindOrAtExcept(unwind, except))
648     return true;
649   if (getLexer().is(AsmToken::Comma)) {
650     Lex();
651     if (ParseAtUnwindOrAtExcept(unwind, except))
652       return true;
653   }
654   if (getLexer().isNot(AsmToken::EndOfStatement))
655     return TokError("unexpected token in directive");
656
657   MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
658
659   Lex();
660   getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
661   return false;
662 }
663
664 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
665   Lex();
666   getStreamer().EmitWinEHHandlerData();
667   return false;
668 }
669
670 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
671   int64_t Size;
672   if (getParser().parseAbsoluteExpression(Size))
673     return true;
674
675   if (getLexer().isNot(AsmToken::EndOfStatement))
676     return TokError("unexpected token in directive");
677
678   Lex();
679   getStreamer().EmitWinCFIAllocStack(Size, Loc);
680   return false;
681 }
682
683 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
684   Lex();
685   getStreamer().EmitWinCFIEndProlog(Loc);
686   return false;
687 }
688
689 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
690   StringRef identifier;
691   if (getLexer().isNot(AsmToken::At))
692     return TokError("a handler attribute must begin with '@'");
693   SMLoc startLoc = getLexer().getLoc();
694   Lex();
695   if (getParser().parseIdentifier(identifier))
696     return Error(startLoc, "expected @unwind or @except");
697   if (identifier == "unwind")
698     unwind = true;
699   else if (identifier == "except")
700     except = true;
701   else
702     return Error(startLoc, "expected @unwind or @except");
703   return false;
704 }
705
706 namespace llvm {
707
708 MCAsmParserExtension *createCOFFAsmParser() {
709   return new COFFAsmParser;
710 }
711
712 } // end namespace llvm