1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/StringSwitch.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCDirectives.h"
16 #include "llvm/MC/MCObjectFileInfo.h"
17 #include "llvm/MC/MCParser/MCAsmLexer.h"
18 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
19 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCSectionCOFF.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/SectionKind.h"
24 #include "llvm/Support/SMLoc.h"
34 class COFFAsmParser : public MCAsmParserExtension {
35 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
36 void addDirectiveHandler(StringRef Directive) {
37 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
38 this, HandleDirective<COFFAsmParser, HandlerMethod>);
39 getParser().addDirectiveHandler(Directive, Handler);
42 bool ParseSectionSwitch(StringRef Section,
43 unsigned Characteristics,
46 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47 SectionKind Kind, StringRef COMDATSymName,
48 COFF::COMDATType Type);
50 bool ParseSectionName(StringRef &SectionName);
51 bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
54 void Initialize(MCAsmParser &Parser) override {
55 // Call the base implementation.
56 MCAsmParserExtension::Initialize(Parser);
58 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
59 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
60 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
61 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
62 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
63 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
64 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
65 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
66 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
67 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
68 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
69 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
70 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
71 addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
72 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
73 addDirectiveHandler<&COFFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
75 // Win64 EH directives.
76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
78 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
80 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
82 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
84 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
86 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
88 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
90 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
94 bool ParseSectionDirectiveText(StringRef, SMLoc) {
95 return ParseSectionSwitch(".text",
96 COFF::IMAGE_SCN_CNT_CODE
97 | COFF::IMAGE_SCN_MEM_EXECUTE
98 | COFF::IMAGE_SCN_MEM_READ,
99 SectionKind::getText());
102 bool ParseSectionDirectiveData(StringRef, SMLoc) {
103 return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
104 COFF::IMAGE_SCN_MEM_READ |
105 COFF::IMAGE_SCN_MEM_WRITE,
106 SectionKind::getData());
109 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
110 return ParseSectionSwitch(".bss",
111 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
112 | COFF::IMAGE_SCN_MEM_READ
113 | COFF::IMAGE_SCN_MEM_WRITE,
114 SectionKind::getBSS());
117 bool ParseDirectiveSection(StringRef, SMLoc);
118 bool ParseDirectiveDef(StringRef, SMLoc);
119 bool ParseDirectiveScl(StringRef, SMLoc);
120 bool ParseDirectiveType(StringRef, SMLoc);
121 bool ParseDirectiveEndef(StringRef, SMLoc);
122 bool ParseDirectiveSecRel32(StringRef, SMLoc);
123 bool ParseDirectiveSecIdx(StringRef, SMLoc);
124 bool ParseDirectiveSafeSEH(StringRef, SMLoc);
125 bool ParseDirectiveSymIdx(StringRef, SMLoc);
126 bool parseCOMDATType(COFF::COMDATType &Type);
127 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
128 bool ParseDirectiveRVA(StringRef, SMLoc);
129 bool ParseDirectiveCGProfile(StringRef, SMLoc);
131 // Win64 EH directives.
132 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
133 bool ParseSEHDirectiveEndProc(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);
141 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
142 bool ParseSEHRegisterNumber(unsigned &RegNo);
143 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
146 COFFAsmParser() = default;
149 } // end anonymous namespace.
151 static SectionKind computeSectionKind(unsigned Flags) {
152 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
153 return SectionKind::getText();
154 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
155 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
156 return SectionKind::getReadOnly();
157 return SectionKind::getData();
160 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
161 StringRef FlagsString, unsigned *Flags) {
172 Discardable = 1 << 8,
175 bool ReadOnlyRemoved = false;
176 unsigned SecFlags = None;
178 for (char FlagChar : FlagsString) {
184 case 'b': // bss section
186 if (SecFlags & InitData)
187 return TokError("conflicting section flags 'b' and 'd'.");
191 case 'd': // data section
192 SecFlags |= InitData;
193 if (SecFlags & Alloc)
194 return TokError("conflicting section flags 'b' and 'd'.");
195 SecFlags &= ~NoWrite;
196 if ((SecFlags & NoLoad) == 0)
200 case 'n': // section is not loaded
205 case 'D': // discardable
206 SecFlags |= Discardable;
209 case 'r': // read-only
210 ReadOnlyRemoved = false;
212 if ((SecFlags & Code) == 0)
213 SecFlags |= InitData;
214 if ((SecFlags & NoLoad) == 0)
218 case 's': // shared section
219 SecFlags |= Shared | InitData;
220 SecFlags &= ~NoWrite;
221 if ((SecFlags & NoLoad) == 0)
225 case 'w': // writable
226 SecFlags &= ~NoWrite;
227 ReadOnlyRemoved = true;
230 case 'x': // executable section
232 if ((SecFlags & NoLoad) == 0)
234 if (!ReadOnlyRemoved)
238 case 'y': // not readable
239 SecFlags |= NoRead | NoWrite;
243 return TokError("unknown flag");
249 if (SecFlags == None)
253 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
254 if (SecFlags & InitData)
255 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
256 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
257 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
258 if (SecFlags & NoLoad)
259 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
260 if ((SecFlags & Discardable) ||
261 MCSectionCOFF::isImplicitlyDiscardable(SectionName))
262 *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
263 if ((SecFlags & NoRead) == 0)
264 *Flags |= COFF::IMAGE_SCN_MEM_READ;
265 if ((SecFlags & NoWrite) == 0)
266 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
267 if (SecFlags & Shared)
268 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
273 /// ParseDirectiveSymbolAttribute
274 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
275 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
276 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
277 .Case(".weak", MCSA_Weak)
278 .Default(MCSA_Invalid);
279 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
280 if (getLexer().isNot(AsmToken::EndOfStatement)) {
284 if (getParser().parseIdentifier(Name))
285 return TokError("expected identifier in directive");
287 MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
289 getStreamer().emitSymbolAttribute(Sym, Attr);
291 if (getLexer().is(AsmToken::EndOfStatement))
294 if (getLexer().isNot(AsmToken::Comma))
295 return TokError("unexpected token in directive");
304 bool COFFAsmParser::ParseDirectiveCGProfile(StringRef S, SMLoc Loc) {
305 return MCAsmParserExtension::ParseDirectiveCGProfile(S, Loc);
308 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
309 unsigned Characteristics,
311 return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
314 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
315 unsigned Characteristics,
317 StringRef COMDATSymName,
318 COFF::COMDATType Type) {
319 if (getLexer().isNot(AsmToken::EndOfStatement))
320 return TokError("unexpected token in section switching directive");
323 getStreamer().SwitchSection(getContext().getCOFFSection(
324 Section, Characteristics, Kind, COMDATSymName, Type));
329 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
330 if (!getLexer().is(AsmToken::Identifier) && !getLexer().is(AsmToken::String))
333 SectionName = getTok().getIdentifier();
338 // .section name [, "flags"] [, identifier [ identifier ], identifier]
342 // b: BSS section (uninitialized data)
343 // d: data section (initialized data)
344 // n: "noload" section (removed by linker)
345 // D: Discardable section
346 // r: Readable section
348 // w: Writable section
349 // x: Executable section
350 // y: Not-readable section (clears 'r')
352 // Subsections are not supported.
353 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
354 StringRef SectionName;
356 if (ParseSectionName(SectionName))
357 return TokError("expected identifier in directive");
359 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
360 COFF::IMAGE_SCN_MEM_READ |
361 COFF::IMAGE_SCN_MEM_WRITE;
363 if (getLexer().is(AsmToken::Comma)) {
366 if (getLexer().isNot(AsmToken::String))
367 return TokError("expected string in directive");
369 StringRef FlagsStr = getTok().getStringContents();
372 if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
376 COFF::COMDATType Type = (COFF::COMDATType)0;
377 StringRef COMDATSymName;
378 if (getLexer().is(AsmToken::Comma)) {
379 Type = COFF::IMAGE_COMDAT_SELECT_ANY;
382 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
384 if (!getLexer().is(AsmToken::Identifier))
385 return TokError("expected comdat type such as 'discard' or 'largest' "
386 "after protection bits");
388 if (parseCOMDATType(Type))
391 if (getLexer().isNot(AsmToken::Comma))
392 return TokError("expected comma in directive");
395 if (getParser().parseIdentifier(COMDATSymName))
396 return TokError("expected identifier in directive");
399 if (getLexer().isNot(AsmToken::EndOfStatement))
400 return TokError("unexpected token in directive");
402 SectionKind Kind = computeSectionKind(Flags);
404 const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
405 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
406 Flags |= COFF::IMAGE_SCN_MEM_16BIT;
408 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
412 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
413 StringRef SymbolName;
415 if (getParser().parseIdentifier(SymbolName))
416 return TokError("expected identifier in directive");
418 MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
420 getStreamer().BeginCOFFSymbolDef(Sym);
426 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
427 int64_t SymbolStorageClass;
428 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
431 if (getLexer().isNot(AsmToken::EndOfStatement))
432 return TokError("unexpected token in directive");
435 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
439 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
441 if (getParser().parseAbsoluteExpression(Type))
444 if (getLexer().isNot(AsmToken::EndOfStatement))
445 return TokError("unexpected token in directive");
448 getStreamer().EmitCOFFSymbolType(Type);
452 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
454 getStreamer().EndCOFFSymbolDef();
458 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
460 if (getParser().parseIdentifier(SymbolID))
461 return TokError("expected identifier in directive");
465 if (getLexer().is(AsmToken::Plus)) {
466 OffsetLoc = getLexer().getLoc();
467 if (getParser().parseAbsoluteExpression(Offset))
471 if (getLexer().isNot(AsmToken::EndOfStatement))
472 return TokError("unexpected token in directive");
474 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
477 "invalid '.secrel32' directive offset, can't be less "
478 "than zero or greater than std::numeric_limits<uint32_t>::max()");
480 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
483 getStreamer().EmitCOFFSecRel32(Symbol, Offset);
487 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
488 auto parseOp = [&]() -> bool {
490 if (getParser().parseIdentifier(SymbolID))
491 return TokError("expected identifier in directive");
495 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
496 OffsetLoc = getLexer().getLoc();
497 if (getParser().parseAbsoluteExpression(Offset))
501 if (Offset < std::numeric_limits<int32_t>::min() ||
502 Offset > std::numeric_limits<int32_t>::max())
503 return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
504 "than -2147483648 or greater than "
507 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
509 getStreamer().EmitCOFFImgRel32(Symbol, Offset);
513 if (getParser().parseMany(parseOp))
514 return addErrorSuffix(" in directive");
518 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
520 if (getParser().parseIdentifier(SymbolID))
521 return TokError("expected identifier in directive");
523 if (getLexer().isNot(AsmToken::EndOfStatement))
524 return TokError("unexpected token in directive");
526 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
529 getStreamer().EmitCOFFSafeSEH(Symbol);
533 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
535 if (getParser().parseIdentifier(SymbolID))
536 return TokError("expected identifier in directive");
538 if (getLexer().isNot(AsmToken::EndOfStatement))
539 return TokError("unexpected token in directive");
541 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
544 getStreamer().EmitCOFFSectionIndex(Symbol);
548 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
550 if (getParser().parseIdentifier(SymbolID))
551 return TokError("expected identifier in directive");
553 if (getLexer().isNot(AsmToken::EndOfStatement))
554 return TokError("unexpected token in directive");
556 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
559 getStreamer().EmitCOFFSymbolIndex(Symbol);
563 /// ::= [ identifier ]
564 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
565 StringRef TypeId = getTok().getIdentifier();
567 Type = StringSwitch<COFF::COMDATType>(TypeId)
568 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
569 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
570 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
571 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
572 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
573 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
574 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
575 .Default((COFF::COMDATType)0);
578 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
585 /// ParseDirectiveLinkOnce
586 /// ::= .linkonce [ identifier ]
587 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
588 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
589 if (getLexer().is(AsmToken::Identifier))
590 if (parseCOMDATType(Type))
593 const MCSectionCOFF *Current =
594 static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
596 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
597 return Error(Loc, "cannot make section associative with .linkonce");
599 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
600 return Error(Loc, Twine("section '") + Current->getName() +
601 "' is already linkonce");
603 Current->setSelection(Type);
605 if (getLexer().isNot(AsmToken::EndOfStatement))
606 return TokError("unexpected token in directive");
611 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
613 if (getParser().parseIdentifier(SymbolID))
616 if (getLexer().isNot(AsmToken::EndOfStatement))
617 return TokError("unexpected token in directive");
619 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
622 getStreamer().EmitWinCFIStartProc(Symbol, Loc);
626 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
628 getStreamer().EmitWinCFIEndProc(Loc);
632 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
634 getStreamer().EmitWinCFIStartChained(Loc);
638 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
640 getStreamer().EmitWinCFIEndChained(Loc);
644 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
646 if (getParser().parseIdentifier(SymbolID))
649 if (getLexer().isNot(AsmToken::Comma))
650 return TokError("you must specify one or both of @unwind or @except");
652 bool unwind = false, except = false;
653 if (ParseAtUnwindOrAtExcept(unwind, except))
655 if (getLexer().is(AsmToken::Comma)) {
657 if (ParseAtUnwindOrAtExcept(unwind, except))
660 if (getLexer().isNot(AsmToken::EndOfStatement))
661 return TokError("unexpected token in directive");
663 MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
666 getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
670 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
672 getStreamer().EmitWinEHHandlerData();
676 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
678 if (getParser().parseAbsoluteExpression(Size))
681 if (getLexer().isNot(AsmToken::EndOfStatement))
682 return TokError("unexpected token in directive");
685 getStreamer().EmitWinCFIAllocStack(Size, Loc);
689 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
691 getStreamer().EmitWinCFIEndProlog(Loc);
695 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
696 StringRef identifier;
697 if (getLexer().isNot(AsmToken::At))
698 return TokError("a handler attribute must begin with '@'");
699 SMLoc startLoc = getLexer().getLoc();
701 if (getParser().parseIdentifier(identifier))
702 return Error(startLoc, "expected @unwind or @except");
703 if (identifier == "unwind")
705 else if (identifier == "except")
708 return Error(startLoc, "expected @unwind or @except");
714 MCAsmParserExtension *createCOFFAsmParser() {
715 return new COFFAsmParser;
718 } // end namespace llvm