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