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