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
27 using namespace llvm;
28
29 namespace {
30
31 class COFFAsmParser : public MCAsmParserExtension {
32 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)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
Initialize(MCAsmParser & Parser)48 void Initialize(MCAsmParser &Parser) override {
49 // Call the base implementation.
50 MCAsmParserExtension::Initialize(Parser);
51
52 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
53 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
54 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
55 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
56 addDirectiveHandler<&COFFAsmParser::ParseDirectivePushSection>(
57 ".pushsection");
58 addDirectiveHandler<&COFFAsmParser::ParseDirectivePopSection>(
59 ".popsection");
60 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
61 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
62 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
63 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
64 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
65 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
66 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
67 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
68 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
69 addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
70 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
71 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak_anti_dep");
72 addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
73
74 // Win64 EH directives.
75 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
76 ".seh_proc");
77 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
78 ".seh_endproc");
79 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc>(
80 ".seh_endfunclet");
81 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
82 ".seh_startchained");
83 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
84 ".seh_endchained");
85 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
86 ".seh_handler");
87 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
88 ".seh_handlerdata");
89 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
90 ".seh_stackalloc");
91 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
92 ".seh_endprologue");
93 }
94
ParseSectionDirectiveText(StringRef,SMLoc)95 bool ParseSectionDirectiveText(StringRef, SMLoc) {
96 return ParseSectionSwitch(".text", COFF::IMAGE_SCN_CNT_CODE |
97 COFF::IMAGE_SCN_MEM_EXECUTE |
98 COFF::IMAGE_SCN_MEM_READ);
99 }
100
ParseSectionDirectiveData(StringRef,SMLoc)101 bool ParseSectionDirectiveData(StringRef, SMLoc) {
102 return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
103 COFF::IMAGE_SCN_MEM_READ |
104 COFF::IMAGE_SCN_MEM_WRITE);
105 }
106
ParseSectionDirectiveBSS(StringRef,SMLoc)107 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
108 return ParseSectionSwitch(".bss", 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
144 public:
145 COFFAsmParser() = default;
146 };
147
148 } // end anonymous namespace.
149
ParseSectionFlags(StringRef SectionName,StringRef FlagsString,unsigned * Flags)150 bool 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("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("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("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(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 )* ]
ParseDirectiveSymbolAttribute(StringRef Directive,SMLoc)272 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
273 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
274 .Case(".weak", MCSA_Weak)
275 .Case(".weak_anti_dep", MCSA_WeakAntiDep)
276 .Default(MCSA_Invalid);
277 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
278 if (getLexer().isNot(AsmToken::EndOfStatement)) {
279 while (true) {
280 StringRef Name;
281
282 if (getParser().parseIdentifier(Name))
283 return TokError("expected identifier in directive");
284
285 MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
286
287 getStreamer().emitSymbolAttribute(Sym, Attr);
288
289 if (getLexer().is(AsmToken::EndOfStatement))
290 break;
291
292 if (getLexer().isNot(AsmToken::Comma))
293 return TokError("unexpected token in directive");
294 Lex();
295 }
296 }
297
298 Lex();
299 return false;
300 }
301
ParseDirectiveCGProfile(StringRef S,SMLoc Loc)302 bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) {
303 return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc);
304 }
305
ParseSectionSwitch(StringRef Section,unsigned Characteristics)306 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
307 unsigned Characteristics) {
308 return ParseSectionSwitch(Section, Characteristics, "", (COFF::COMDATType)0);
309 }
310
ParseSectionSwitch(StringRef Section,unsigned Characteristics,StringRef COMDATSymName,COFF::COMDATType Type)311 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
312 unsigned Characteristics,
313 StringRef COMDATSymName,
314 COFF::COMDATType Type) {
315 if (getLexer().isNot(AsmToken::EndOfStatement))
316 return TokError("unexpected token in section switching directive");
317 Lex();
318
319 getStreamer().switchSection(getContext().getCOFFSection(
320 Section, Characteristics, COMDATSymName, Type));
321
322 return false;
323 }
324
ParseSectionName(StringRef & SectionName)325 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
326 if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String))
327 return true;
328
329 SectionName = getTok().getIdentifier();
330 Lex();
331 return false;
332 }
333
ParseDirectiveSection(StringRef directive,SMLoc loc)334 bool 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.
parseSectionArguments(StringRef,SMLoc)354 bool COFFAsmParser::parseSectionArguments(StringRef, SMLoc) {
355 StringRef SectionName;
356
357 if (ParseSectionName(SectionName))
358 return TokError("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(AsmToken::Comma)) {
365 Lex();
366
367 if (getLexer().isNot(AsmToken::String))
368 return TokError("expected string in directive");
369
370 StringRef FlagsStr = getTok().getStringContents();
371 Lex();
372
373 if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
374 return true;
375 }
376
377 COFF::COMDATType Type = (COFF::COMDATType)0;
378 StringRef COMDATSymName;
379 if (getLexer().is(AsmToken::Comma)) {
380 Type = COFF::IMAGE_COMDAT_SELECT_ANY;
381 Lex();
382
383 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
384
385 if (!getLexer().is(AsmToken::Identifier))
386 return TokError("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(AsmToken::Comma))
393 return TokError("expected comma in directive");
394 Lex();
395
396 if (getParser().parseIdentifier(COMDATSymName))
397 return TokError("expected identifier in directive");
398 }
399
400 if (getLexer().isNot(AsmToken::EndOfStatement))
401 return TokError("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(SectionName, Flags, COMDATSymName, Type);
409 return false;
410 }
411
ParseDirectivePushSection(StringRef directive,SMLoc loc)412 bool 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
ParseDirectivePopSection(StringRef,SMLoc)423 bool COFFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) {
424 if (!getStreamer().popSection())
425 return TokError(".popsection without corresponding .pushsection");
426 return false;
427 }
428
ParseDirectiveDef(StringRef,SMLoc)429 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
430 StringRef SymbolName;
431
432 if (getParser().parseIdentifier(SymbolName))
433 return TokError("expected identifier in directive");
434
435 MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
436
437 getStreamer().beginCOFFSymbolDef(Sym);
438
439 Lex();
440 return false;
441 }
442
ParseDirectiveScl(StringRef,SMLoc)443 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
444 int64_t SymbolStorageClass;
445 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
446 return true;
447
448 if (getLexer().isNot(AsmToken::EndOfStatement))
449 return TokError("unexpected token in directive");
450
451 Lex();
452 getStreamer().emitCOFFSymbolStorageClass(SymbolStorageClass);
453 return false;
454 }
455
ParseDirectiveType(StringRef,SMLoc)456 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
457 int64_t Type;
458 if (getParser().parseAbsoluteExpression(Type))
459 return true;
460
461 if (getLexer().isNot(AsmToken::EndOfStatement))
462 return TokError("unexpected token in directive");
463
464 Lex();
465 getStreamer().emitCOFFSymbolType(Type);
466 return false;
467 }
468
ParseDirectiveEndef(StringRef,SMLoc)469 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
470 Lex();
471 getStreamer().endCOFFSymbolDef();
472 return false;
473 }
474
ParseDirectiveSecRel32(StringRef,SMLoc)475 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
476 StringRef SymbolID;
477 if (getParser().parseIdentifier(SymbolID))
478 return TokError("expected identifier in directive");
479
480 int64_t Offset = 0;
481 SMLoc OffsetLoc;
482 if (getLexer().is(AsmToken::Plus)) {
483 OffsetLoc = getLexer().getLoc();
484 if (getParser().parseAbsoluteExpression(Offset))
485 return true;
486 }
487
488 if (getLexer().isNot(AsmToken::EndOfStatement))
489 return TokError("unexpected token in directive");
490
491 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
492 return Error(
493 OffsetLoc,
494 "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(SymbolID);
498
499 Lex();
500 getStreamer().emitCOFFSecRel32(Symbol, Offset);
501 return false;
502 }
503
ParseDirectiveRVA(StringRef,SMLoc)504 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
505 auto parseOp = [&]() -> bool {
506 StringRef SymbolID;
507 if (getParser().parseIdentifier(SymbolID))
508 return TokError("expected identifier in directive");
509
510 int64_t Offset = 0;
511 SMLoc OffsetLoc;
512 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
513 OffsetLoc = getLexer().getLoc();
514 if (getParser().parseAbsoluteExpression(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(OffsetLoc, "invalid '.rva' directive offset, can't be less "
521 "than -2147483648 or greater than "
522 "2147483647");
523
524 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
525
526 getStreamer().emitCOFFImgRel32(Symbol, Offset);
527 return false;
528 };
529
530 if (getParser().parseMany(parseOp))
531 return addErrorSuffix(" in directive");
532 return false;
533 }
534
ParseDirectiveSafeSEH(StringRef,SMLoc)535 bool COFFAsmParser::ParseDirectiveSafeSEH(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().emitCOFFSafeSEH(Symbol);
547 return false;
548 }
549
ParseDirectiveSecIdx(StringRef,SMLoc)550 bool COFFAsmParser::ParseDirectiveSecIdx(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().emitCOFFSectionIndex(Symbol);
562 return false;
563 }
564
ParseDirectiveSymIdx(StringRef,SMLoc)565 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
566 StringRef SymbolID;
567 if (getParser().parseIdentifier(SymbolID))
568 return TokError("expected identifier in directive");
569
570 if (getLexer().isNot(AsmToken::EndOfStatement))
571 return TokError("unexpected token in directive");
572
573 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
574
575 Lex();
576 getStreamer().emitCOFFSymbolIndex(Symbol);
577 return false;
578 }
579
580 /// ::= [ identifier ]
parseCOMDATType(COFF::COMDATType & Type)581 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
582 StringRef TypeId = getTok().getIdentifier();
583
584 Type = StringSwitch<COFF::COMDATType>(TypeId)
585 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
586 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
587 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
588 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
589 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
590 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
591 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
592 .Default((COFF::COMDATType)0);
593
594 if (Type == 0)
595 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
596
597 Lex();
598
599 return false;
600 }
601
602 /// ParseDirectiveLinkOnce
603 /// ::= .linkonce [ identifier ]
ParseDirectiveLinkOnce(StringRef,SMLoc Loc)604 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
605 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
606 if (getLexer().is(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(Loc, "cannot make section associative with .linkonce");
615
616 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
617 return Error(Loc, Twine("section '") + Current->getName() +
618 "' is already linkonce");
619
620 Current->setSelection(Type);
621
622 if (getLexer().isNot(AsmToken::EndOfStatement))
623 return TokError("unexpected token in directive");
624
625 return false;
626 }
627
ParseSEHDirectiveStartProc(StringRef,SMLoc Loc)628 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
629 StringRef SymbolID;
630 if (getParser().parseIdentifier(SymbolID))
631 return true;
632
633 if (getLexer().isNot(AsmToken::EndOfStatement))
634 return TokError("unexpected token in directive");
635
636 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
637
638 Lex();
639 getStreamer().emitWinCFIStartProc(Symbol, Loc);
640 return false;
641 }
642
ParseSEHDirectiveEndProc(StringRef,SMLoc Loc)643 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
644 Lex();
645 getStreamer().emitWinCFIEndProc(Loc);
646 return false;
647 }
648
ParseSEHDirectiveEndFuncletOrFunc(StringRef,SMLoc Loc)649 bool COFFAsmParser::ParseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) {
650 Lex();
651 getStreamer().emitWinCFIFuncletOrFuncEnd(Loc);
652 return false;
653 }
654
ParseSEHDirectiveStartChained(StringRef,SMLoc Loc)655 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
656 Lex();
657 getStreamer().emitWinCFIStartChained(Loc);
658 return false;
659 }
660
ParseSEHDirectiveEndChained(StringRef,SMLoc Loc)661 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
662 Lex();
663 getStreamer().emitWinCFIEndChained(Loc);
664 return false;
665 }
666
ParseSEHDirectiveHandler(StringRef,SMLoc Loc)667 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
668 StringRef SymbolID;
669 if (getParser().parseIdentifier(SymbolID))
670 return true;
671
672 if (getLexer().isNot(AsmToken::Comma))
673 return TokError("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(AsmToken::Comma)) {
679 Lex();
680 if (ParseAtUnwindOrAtExcept(unwind, except))
681 return true;
682 }
683 if (getLexer().isNot(AsmToken::EndOfStatement))
684 return TokError("unexpected token in directive");
685
686 MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
687
688 Lex();
689 getStreamer().emitWinEHHandler(handler, unwind, except, Loc);
690 return false;
691 }
692
ParseSEHDirectiveHandlerData(StringRef,SMLoc Loc)693 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
694 Lex();
695 getStreamer().emitWinEHHandlerData();
696 return false;
697 }
698
ParseSEHDirectiveAllocStack(StringRef,SMLoc Loc)699 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
700 int64_t Size;
701 if (getParser().parseAbsoluteExpression(Size))
702 return true;
703
704 if (getLexer().isNot(AsmToken::EndOfStatement))
705 return TokError("unexpected token in directive");
706
707 Lex();
708 getStreamer().emitWinCFIAllocStack(Size, Loc);
709 return false;
710 }
711
ParseSEHDirectiveEndProlog(StringRef,SMLoc Loc)712 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
713 Lex();
714 getStreamer().emitWinCFIEndProlog(Loc);
715 return false;
716 }
717
ParseAtUnwindOrAtExcept(bool & unwind,bool & except)718 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
719 StringRef identifier;
720 if (getLexer().isNot(AsmToken::At) && getLexer().isNot(AsmToken::Percent))
721 return TokError("a handler attribute must begin with '@' or '%'");
722 SMLoc startLoc = getLexer().getLoc();
723 Lex();
724 if (getParser().parseIdentifier(identifier))
725 return Error(startLoc, "expected @unwind or @except");
726 if (identifier == "unwind")
727 unwind = true;
728 else if (identifier == "except")
729 except = true;
730 else
731 return Error(startLoc, "expected @unwind or @except");
732 return false;
733 }
734
735 namespace llvm {
736
createCOFFAsmParser()737 MCAsmParserExtension *createCOFFAsmParser() {
738 return new COFFAsmParser;
739 }
740
741 } // end namespace llvm
742