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
26 using namespace llvm;
27
28 namespace {
29
30 class COFFAsmParser : public MCAsmParserExtension {
31 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)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);
Initialize(MCAsmParser & Parser)47 void Initialize(MCAsmParser &Parser) override {
48 // Call the base implementation.
49 MCAsmParserExtension::Initialize(Parser);
50
51 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveText>(".text");
52 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveData>(".data");
53 addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveBSS>(".bss");
54 addDirectiveHandler<&COFFAsmParser::parseDirectiveSection>(".section");
55 addDirectiveHandler<&COFFAsmParser::parseDirectivePushSection>(
56 ".pushsection");
57 addDirectiveHandler<&COFFAsmParser::parseDirectivePopSection>(
58 ".popsection");
59 addDirectiveHandler<&COFFAsmParser::parseDirectiveDef>(".def");
60 addDirectiveHandler<&COFFAsmParser::parseDirectiveScl>(".scl");
61 addDirectiveHandler<&COFFAsmParser::parseDirectiveType>(".type");
62 addDirectiveHandler<&COFFAsmParser::parseDirectiveEndef>(".endef");
63 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecRel32>(".secrel32");
64 addDirectiveHandler<&COFFAsmParser::parseDirectiveSymIdx>(".symidx");
65 addDirectiveHandler<&COFFAsmParser::parseDirectiveSafeSEH>(".safeseh");
66 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecIdx>(".secidx");
67 addDirectiveHandler<&COFFAsmParser::parseDirectiveLinkOnce>(".linkonce");
68 addDirectiveHandler<&COFFAsmParser::parseDirectiveRVA>(".rva");
69 addDirectiveHandler<&COFFAsmParser::parseDirectiveSymbolAttribute>(".weak");
70 addDirectiveHandler<&COFFAsmParser::parseDirectiveSymbolAttribute>(
71 ".weak_anti_dep");
72 addDirectiveHandler<&COFFAsmParser::parseDirectiveCGProfile>(".cg_profile");
73 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecNum>(".secnum");
74 addDirectiveHandler<&COFFAsmParser::parseDirectiveSecOffset>(".secoffset");
75
76 // Win64 EH directives.
77 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartProc>(
78 ".seh_proc");
79 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProc>(
80 ".seh_endproc");
81 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc>(
82 ".seh_endfunclet");
83 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartChained>(
84 ".seh_startchained");
85 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndChained>(
86 ".seh_endchained");
87 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandler>(
88 ".seh_handler");
89 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandlerData>(
90 ".seh_handlerdata");
91 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveAllocStack>(
92 ".seh_stackalloc");
93 addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProlog>(
94 ".seh_endprologue");
95 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveBeginEpilog>(
96 ".seh_startepilogue");
97 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndEpilog>(
98 ".seh_endepilogue");
99 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindV2Start>(
100 ".seh_unwindv2start");
101 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindVersion>(
102 ".seh_unwindversion");
103 }
104
parseSectionDirectiveText(StringRef,SMLoc)105 bool parseSectionDirectiveText(StringRef, SMLoc) {
106 return parseSectionSwitch(".text", COFF::IMAGE_SCN_CNT_CODE |
107 COFF::IMAGE_SCN_MEM_EXECUTE |
108 COFF::IMAGE_SCN_MEM_READ);
109 }
110
parseSectionDirectiveData(StringRef,SMLoc)111 bool parseSectionDirectiveData(StringRef, SMLoc) {
112 return parseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
113 COFF::IMAGE_SCN_MEM_READ |
114 COFF::IMAGE_SCN_MEM_WRITE);
115 }
116
parseSectionDirectiveBSS(StringRef,SMLoc)117 bool parseSectionDirectiveBSS(StringRef, SMLoc) {
118 return parseSectionSwitch(".bss", 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
160 public:
161 COFFAsmParser() = default;
162 };
163
164 } // end anonymous namespace.
165
parseSectionFlags(StringRef SectionName,StringRef FlagsString,unsigned * Flags)166 bool 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("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("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("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(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 )* ]
parseDirectiveSymbolAttribute(StringRef Directive,SMLoc)288 bool COFFAsmParser::parseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
289 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
290 .Case(".weak", MCSA_Weak)
291 .Case(".weak_anti_dep", MCSA_WeakAntiDep)
292 .Default(MCSA_Invalid);
293 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
294 if (getLexer().isNot(AsmToken::EndOfStatement)) {
295 while (true) {
296 MCSymbol *Sym;
297
298 if (getParser().parseSymbol(Sym))
299 return TokError("expected identifier in directive");
300
301 getStreamer().emitSymbolAttribute(Sym, Attr);
302
303 if (getLexer().is(AsmToken::EndOfStatement))
304 break;
305
306 if (getLexer().isNot(AsmToken::Comma))
307 return TokError("unexpected token in directive");
308 Lex();
309 }
310 }
311
312 Lex();
313 return false;
314 }
315
parseDirectiveCGProfile(StringRef S,SMLoc Loc)316 bool COFFAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) {
317 return MCAsmParserExtension::parseDirectiveCGProfile(S, Loc);
318 }
319
parseSectionSwitch(StringRef Section,unsigned Characteristics)320 bool COFFAsmParser::parseSectionSwitch(StringRef Section,
321 unsigned Characteristics) {
322 return parseSectionSwitch(Section, Characteristics, "", (COFF::COMDATType)0,
323 MCSection::NonUniqueID);
324 }
325
parseSectionSwitch(StringRef Section,unsigned Characteristics,StringRef COMDATSymName,COFF::COMDATType Type,unsigned UniqueID)326 bool COFFAsmParser::parseSectionSwitch(StringRef Section,
327 unsigned Characteristics,
328 StringRef COMDATSymName,
329 COFF::COMDATType Type,
330 unsigned UniqueID) {
331 if (getLexer().isNot(AsmToken::EndOfStatement))
332 return TokError("unexpected token in section switching directive");
333 Lex();
334
335 getStreamer().switchSection(getContext().getCOFFSection(
336 Section, Characteristics, COMDATSymName, Type, UniqueID));
337
338 return false;
339 }
340
parseSectionName(StringRef & SectionName)341 bool COFFAsmParser::parseSectionName(StringRef &SectionName) {
342 if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String))
343 return true;
344
345 SectionName = getTok().getIdentifier();
346 Lex();
347 return false;
348 }
349
parseDirectiveSection(StringRef directive,SMLoc loc)350 bool COFFAsmParser::parseDirectiveSection(StringRef directive, SMLoc loc) {
351 return parseSectionArguments(directive, loc);
352 }
353
354 // .section name [, "flags"] [, identifier [ identifier ], identifier]
355 // .pushsection <same as above>
356 //
357 // Supported flags:
358 // a: Ignored.
359 // b: BSS section (uninitialized data)
360 // d: data section (initialized data)
361 // n: "noload" section (removed by linker)
362 // D: Discardable section
363 // r: Readable section
364 // s: Shared section
365 // w: Writable section
366 // x: Executable section
367 // y: Not-readable section (clears 'r')
368 //
369 // Subsections are not supported.
parseSectionArguments(StringRef,SMLoc)370 bool COFFAsmParser::parseSectionArguments(StringRef, SMLoc) {
371 StringRef SectionName;
372
373 if (parseSectionName(SectionName))
374 return TokError("expected identifier in directive");
375
376 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
377 COFF::IMAGE_SCN_MEM_READ |
378 COFF::IMAGE_SCN_MEM_WRITE;
379
380 if (getLexer().is(AsmToken::Comma)) {
381 Lex();
382
383 if (getLexer().isNot(AsmToken::String))
384 return TokError("expected string in directive");
385
386 StringRef FlagsStr = getTok().getStringContents();
387 Lex();
388
389 if (parseSectionFlags(SectionName, FlagsStr, &Flags))
390 return true;
391 }
392
393 COFF::COMDATType Type = (COFF::COMDATType)0;
394 StringRef COMDATSymName;
395 if (getLexer().is(AsmToken::Comma) &&
396 getLexer().peekTok().getString() != "unique") {
397 Type = COFF::IMAGE_COMDAT_SELECT_ANY;
398 Lex();
399
400 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
401
402 if (!getLexer().is(AsmToken::Identifier))
403 return TokError("expected comdat type such as 'discard' or 'largest' "
404 "after protection bits");
405
406 if (parseCOMDATType(Type))
407 return true;
408
409 if (getLexer().isNot(AsmToken::Comma))
410 return TokError("expected comma in directive");
411 Lex();
412
413 if (getParser().parseIdentifier(COMDATSymName))
414 return TokError("expected identifier in directive");
415 }
416
417 int64_t UniqueID = MCSection::NonUniqueID;
418 if (maybeParseUniqueID(UniqueID))
419 return true;
420
421 if (getLexer().isNot(AsmToken::EndOfStatement))
422 return TokError("unexpected token in directive");
423
424 if (Flags & COFF::IMAGE_SCN_CNT_CODE) {
425 const Triple &T = getContext().getTargetTriple();
426 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
427 Flags |= COFF::IMAGE_SCN_MEM_16BIT;
428 }
429 parseSectionSwitch(SectionName, Flags, COMDATSymName, Type, UniqueID);
430 return false;
431 }
432
parseDirectivePushSection(StringRef directive,SMLoc loc)433 bool COFFAsmParser::parseDirectivePushSection(StringRef directive, SMLoc loc) {
434 getStreamer().pushSection();
435
436 if (parseSectionArguments(directive, loc)) {
437 getStreamer().popSection();
438 return true;
439 }
440
441 return false;
442 }
443
parseDirectivePopSection(StringRef,SMLoc)444 bool COFFAsmParser::parseDirectivePopSection(StringRef, SMLoc) {
445 if (!getStreamer().popSection())
446 return TokError(".popsection without corresponding .pushsection");
447 return false;
448 }
449
parseDirectiveDef(StringRef,SMLoc)450 bool COFFAsmParser::parseDirectiveDef(StringRef, SMLoc) {
451 MCSymbol *Sym;
452
453 if (getParser().parseSymbol(Sym))
454 return TokError("expected identifier in directive");
455
456 getStreamer().beginCOFFSymbolDef(Sym);
457
458 Lex();
459 return false;
460 }
461
parseDirectiveScl(StringRef,SMLoc)462 bool COFFAsmParser::parseDirectiveScl(StringRef, SMLoc) {
463 int64_t SymbolStorageClass;
464 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
465 return true;
466
467 if (getLexer().isNot(AsmToken::EndOfStatement))
468 return TokError("unexpected token in directive");
469
470 Lex();
471 getStreamer().emitCOFFSymbolStorageClass(SymbolStorageClass);
472 return false;
473 }
474
parseDirectiveType(StringRef,SMLoc)475 bool COFFAsmParser::parseDirectiveType(StringRef, SMLoc) {
476 int64_t Type;
477 if (getParser().parseAbsoluteExpression(Type))
478 return true;
479
480 if (getLexer().isNot(AsmToken::EndOfStatement))
481 return TokError("unexpected token in directive");
482
483 Lex();
484 getStreamer().emitCOFFSymbolType(Type);
485 return false;
486 }
487
parseDirectiveEndef(StringRef,SMLoc)488 bool COFFAsmParser::parseDirectiveEndef(StringRef, SMLoc) {
489 Lex();
490 getStreamer().endCOFFSymbolDef();
491 return false;
492 }
493
parseDirectiveSecRel32(StringRef,SMLoc)494 bool COFFAsmParser::parseDirectiveSecRel32(StringRef, SMLoc) {
495 MCSymbol *Symbol;
496 if (getParser().parseSymbol(Symbol))
497 return TokError("expected identifier in directive");
498
499 int64_t Offset = 0;
500 SMLoc OffsetLoc;
501 if (getLexer().is(AsmToken::Plus)) {
502 OffsetLoc = getLexer().getLoc();
503 if (getParser().parseAbsoluteExpression(Offset))
504 return true;
505 }
506
507 if (getLexer().isNot(AsmToken::EndOfStatement))
508 return TokError("unexpected token in directive");
509
510 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
511 return Error(
512 OffsetLoc,
513 "invalid '.secrel32' directive offset, can't be less "
514 "than zero or greater than std::numeric_limits<uint32_t>::max()");
515
516 Lex();
517 getStreamer().emitCOFFSecRel32(Symbol, Offset);
518 return false;
519 }
520
parseDirectiveRVA(StringRef,SMLoc)521 bool COFFAsmParser::parseDirectiveRVA(StringRef, SMLoc) {
522 auto parseOp = [&]() -> bool {
523 MCSymbol *Symbol;
524 if (getParser().parseSymbol(Symbol))
525 return TokError("expected identifier in directive");
526
527 int64_t Offset = 0;
528 SMLoc OffsetLoc;
529 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
530 OffsetLoc = getLexer().getLoc();
531 if (getParser().parseAbsoluteExpression(Offset))
532 return true;
533 }
534
535 if (Offset < std::numeric_limits<int32_t>::min() ||
536 Offset > std::numeric_limits<int32_t>::max())
537 return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
538 "than -2147483648 or greater than "
539 "2147483647");
540
541 getStreamer().emitCOFFImgRel32(Symbol, Offset);
542 return false;
543 };
544
545 if (getParser().parseMany(parseOp))
546 return addErrorSuffix(" in directive");
547 return false;
548 }
549
parseDirectiveSafeSEH(StringRef,SMLoc)550 bool COFFAsmParser::parseDirectiveSafeSEH(StringRef, SMLoc) {
551 MCSymbol *Symbol;
552 if (getParser().parseSymbol(Symbol))
553 return TokError("expected identifier in directive");
554
555 if (getLexer().isNot(AsmToken::EndOfStatement))
556 return TokError("unexpected token in directive");
557
558 Lex();
559 getStreamer().emitCOFFSafeSEH(Symbol);
560 return false;
561 }
562
parseDirectiveSecIdx(StringRef,SMLoc)563 bool COFFAsmParser::parseDirectiveSecIdx(StringRef, SMLoc) {
564 MCSymbol *Symbol;
565 if (getParser().parseSymbol(Symbol))
566 return TokError("expected identifier in directive");
567
568 if (getLexer().isNot(AsmToken::EndOfStatement))
569 return TokError("unexpected token in directive");
570
571 Lex();
572 getStreamer().emitCOFFSectionIndex(Symbol);
573 return false;
574 }
575
parseDirectiveSymIdx(StringRef,SMLoc)576 bool COFFAsmParser::parseDirectiveSymIdx(StringRef, SMLoc) {
577 MCSymbol *Symbol;
578 if (getParser().parseSymbol(Symbol))
579 return TokError("expected identifier in directive");
580
581 if (getLexer().isNot(AsmToken::EndOfStatement))
582 return TokError("unexpected token in directive");
583
584 Lex();
585 getStreamer().emitCOFFSymbolIndex(Symbol);
586 return false;
587 }
588
parseDirectiveSecNum(StringRef,SMLoc)589 bool COFFAsmParser::parseDirectiveSecNum(StringRef, SMLoc) {
590 MCSymbol *Symbol;
591 if (getParser().parseSymbol(Symbol))
592 return TokError("expected identifier in directive");
593
594 if (getLexer().isNot(AsmToken::EndOfStatement))
595 return TokError("unexpected token in directive");
596
597 Lex();
598 getStreamer().emitCOFFSecNumber(Symbol);
599 return false;
600 }
601
parseDirectiveSecOffset(StringRef,SMLoc)602 bool COFFAsmParser::parseDirectiveSecOffset(StringRef, SMLoc) {
603 MCSymbol *Symbol;
604 if (getParser().parseSymbol(Symbol))
605 return TokError("expected identifier in directive");
606
607 if (getLexer().isNot(AsmToken::EndOfStatement))
608 return TokError("unexpected token in directive");
609
610 Lex();
611 getStreamer().emitCOFFSecOffset(Symbol);
612 return false;
613 }
614
615 /// ::= [ identifier ]
parseCOMDATType(COFF::COMDATType & Type)616 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
617 StringRef TypeId = getTok().getIdentifier();
618
619 Type = StringSwitch<COFF::COMDATType>(TypeId)
620 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
621 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
622 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
623 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
624 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
625 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
626 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
627 .Default((COFF::COMDATType)0);
628
629 if (Type == 0)
630 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
631
632 Lex();
633
634 return false;
635 }
636
637 /// ParseDirectiveLinkOnce
638 /// ::= .linkonce [ identifier ]
parseDirectiveLinkOnce(StringRef,SMLoc Loc)639 bool COFFAsmParser::parseDirectiveLinkOnce(StringRef, SMLoc Loc) {
640 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
641 if (getLexer().is(AsmToken::Identifier))
642 if (parseCOMDATType(Type))
643 return true;
644
645 const MCSectionCOFF *Current =
646 static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
647
648 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
649 return Error(Loc, "cannot make section associative with .linkonce");
650
651 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
652 return Error(Loc, Twine("section '") + Current->getName() +
653 "' is already linkonce");
654
655 Current->setSelection(Type);
656
657 if (getLexer().isNot(AsmToken::EndOfStatement))
658 return TokError("unexpected token in directive");
659
660 return false;
661 }
662
parseSEHDirectiveStartProc(StringRef,SMLoc Loc)663 bool COFFAsmParser::parseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
664 MCSymbol *Symbol;
665 if (getParser().parseSymbol(Symbol))
666 return true;
667
668 if (getLexer().isNot(AsmToken::EndOfStatement))
669 return TokError("unexpected token in directive");
670
671 Lex();
672 getStreamer().emitWinCFIStartProc(Symbol, Loc);
673 return false;
674 }
675
parseSEHDirectiveEndProc(StringRef,SMLoc Loc)676 bool COFFAsmParser::parseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
677 Lex();
678 getStreamer().emitWinCFIEndProc(Loc);
679 return false;
680 }
681
parseSEHDirectiveEndFuncletOrFunc(StringRef,SMLoc Loc)682 bool COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) {
683 Lex();
684 getStreamer().emitWinCFIFuncletOrFuncEnd(Loc);
685 return false;
686 }
687
parseSEHDirectiveStartChained(StringRef,SMLoc Loc)688 bool COFFAsmParser::parseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
689 Lex();
690 getStreamer().emitWinCFIStartChained(Loc);
691 return false;
692 }
693
parseSEHDirectiveEndChained(StringRef,SMLoc Loc)694 bool COFFAsmParser::parseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
695 Lex();
696 getStreamer().emitWinCFIEndChained(Loc);
697 return false;
698 }
699
parseSEHDirectiveHandler(StringRef,SMLoc Loc)700 bool COFFAsmParser::parseSEHDirectiveHandler(StringRef, SMLoc Loc) {
701 MCSymbol *handler;
702 if (getParser().parseSymbol(handler))
703 return true;
704
705 if (getLexer().isNot(AsmToken::Comma))
706 return TokError("you must specify one or both of @unwind or @except");
707 Lex();
708 bool unwind = false, except = false;
709 if (parseAtUnwindOrAtExcept(unwind, except))
710 return true;
711 if (getLexer().is(AsmToken::Comma)) {
712 Lex();
713 if (parseAtUnwindOrAtExcept(unwind, except))
714 return true;
715 }
716 if (getLexer().isNot(AsmToken::EndOfStatement))
717 return TokError("unexpected token in directive");
718
719 Lex();
720 getStreamer().emitWinEHHandler(handler, unwind, except, Loc);
721 return false;
722 }
723
parseSEHDirectiveHandlerData(StringRef,SMLoc Loc)724 bool COFFAsmParser::parseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
725 Lex();
726 getStreamer().emitWinEHHandlerData();
727 return false;
728 }
729
parseSEHDirectiveAllocStack(StringRef,SMLoc Loc)730 bool COFFAsmParser::parseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
731 int64_t Size;
732 if (getParser().parseAbsoluteExpression(Size))
733 return true;
734
735 if (getLexer().isNot(AsmToken::EndOfStatement))
736 return TokError("unexpected token in directive");
737
738 Lex();
739 getStreamer().emitWinCFIAllocStack(Size, Loc);
740 return false;
741 }
742
parseSEHDirectiveEndProlog(StringRef,SMLoc Loc)743 bool COFFAsmParser::parseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
744 Lex();
745 getStreamer().emitWinCFIEndProlog(Loc);
746 return false;
747 }
748
ParseSEHDirectiveBeginEpilog(StringRef,SMLoc Loc)749 bool COFFAsmParser::ParseSEHDirectiveBeginEpilog(StringRef, SMLoc Loc) {
750 Lex();
751 getStreamer().emitWinCFIBeginEpilogue(Loc);
752 return false;
753 }
754
ParseSEHDirectiveEndEpilog(StringRef,SMLoc Loc)755 bool COFFAsmParser::ParseSEHDirectiveEndEpilog(StringRef, SMLoc Loc) {
756 Lex();
757 getStreamer().emitWinCFIEndEpilogue(Loc);
758 return false;
759 }
760
ParseSEHDirectiveUnwindV2Start(StringRef,SMLoc Loc)761 bool COFFAsmParser::ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc Loc) {
762 Lex();
763 getStreamer().emitWinCFIUnwindV2Start(Loc);
764 return false;
765 }
766
ParseSEHDirectiveUnwindVersion(StringRef,SMLoc Loc)767 bool COFFAsmParser::ParseSEHDirectiveUnwindVersion(StringRef, SMLoc Loc) {
768 int64_t Version;
769 if (getParser().parseIntToken(Version, "expected unwind version number"))
770 return true;
771
772 if ((Version < 1) || (Version > UINT8_MAX))
773 return Error(Loc, "invalid unwind version");
774
775 if (getLexer().isNot(AsmToken::EndOfStatement))
776 return TokError("unexpected token in directive");
777
778 Lex();
779 getStreamer().emitWinCFIUnwindVersion(Version, Loc);
780 return false;
781 }
782
parseAtUnwindOrAtExcept(bool & unwind,bool & except)783 bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) {
784 StringRef identifier;
785 if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))
786 return TokError("a handler attribute must begin with '@' or '%'");
787 SMLoc startLoc = getLexer().getLoc();
788 Lex();
789 if (getParser().parseIdentifier(identifier))
790 return Error(startLoc, "expected @unwind or @except");
791 if (identifier == "unwind")
792 unwind = true;
793 else if (identifier == "except")
794 except = true;
795 else
796 return Error(startLoc, "expected @unwind or @except");
797 return false;
798 }
799
800 namespace llvm {
801
createCOFFAsmParser()802 MCAsmParserExtension *createCOFFAsmParser() {
803 return new COFFAsmParser;
804 }
805
806 } // end namespace llvm
807