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