xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/MCParser/COFFMasmParser.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===- COFFMasmParser.cpp - COFF MASM Assembly Parser ---------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h"
105ffd83dbSDimitry Andric #include "llvm/ADT/Twine.h"
115ffd83dbSDimitry Andric #include "llvm/BinaryFormat/COFF.h"
12bdd1243dSDimitry Andric #include "llvm/MC/MCAsmMacro.h"
135ffd83dbSDimitry Andric #include "llvm/MC/MCContext.h"
145ffd83dbSDimitry Andric #include "llvm/MC/MCParser/MCAsmLexer.h"
155ffd83dbSDimitry Andric #include "llvm/MC/MCParser/MCAsmParserExtension.h"
16bdd1243dSDimitry Andric #include "llvm/MC/MCParser/MCTargetAsmParser.h"
175ffd83dbSDimitry Andric #include "llvm/MC/MCSectionCOFF.h"
185ffd83dbSDimitry Andric #include "llvm/MC/MCStreamer.h"
19e8d8bef9SDimitry Andric #include "llvm/MC/MCSymbolCOFF.h"
205ffd83dbSDimitry Andric #include "llvm/MC/SectionKind.h"
2181ad6265SDimitry Andric #include "llvm/Support/Casting.h"
225ffd83dbSDimitry Andric #include "llvm/Support/SMLoc.h"
235ffd83dbSDimitry Andric #include <cstdint>
245ffd83dbSDimitry Andric #include <utility>
255ffd83dbSDimitry Andric 
265ffd83dbSDimitry Andric using namespace llvm;
275ffd83dbSDimitry Andric 
285ffd83dbSDimitry Andric namespace {
295ffd83dbSDimitry Andric 
305ffd83dbSDimitry Andric class COFFMasmParser : public MCAsmParserExtension {
315ffd83dbSDimitry Andric   template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
325ffd83dbSDimitry Andric   void addDirectiveHandler(StringRef Directive) {
335ffd83dbSDimitry Andric     MCAsmParser::ExtensionDirectiveHandler Handler =
345ffd83dbSDimitry Andric         std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
355ffd83dbSDimitry Andric     getParser().addDirectiveHandler(Directive, Handler);
365ffd83dbSDimitry Andric   }
375ffd83dbSDimitry Andric 
38*0fca6ea1SDimitry Andric   bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics);
395ffd83dbSDimitry Andric 
40bdd1243dSDimitry Andric   bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics,
41*0fca6ea1SDimitry Andric                           StringRef COMDATSymName, COFF::COMDATType Type,
42*0fca6ea1SDimitry Andric                           Align Alignment);
435ffd83dbSDimitry Andric 
445ffd83dbSDimitry Andric   bool ParseDirectiveProc(StringRef, SMLoc);
455ffd83dbSDimitry Andric   bool ParseDirectiveEndProc(StringRef, SMLoc);
465ffd83dbSDimitry Andric   bool ParseDirectiveSegment(StringRef, SMLoc);
475ffd83dbSDimitry Andric   bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
485ffd83dbSDimitry Andric   bool ParseDirectiveIncludelib(StringRef, SMLoc);
49bdd1243dSDimitry Andric   bool ParseDirectiveOption(StringRef, SMLoc);
505ffd83dbSDimitry Andric 
51e8d8bef9SDimitry Andric   bool ParseDirectiveAlias(StringRef, SMLoc);
52e8d8bef9SDimitry Andric 
53e8d8bef9SDimitry Andric   bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
54e8d8bef9SDimitry Andric   bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
55e8d8bef9SDimitry Andric 
565ffd83dbSDimitry Andric   bool IgnoreDirective(StringRef, SMLoc) {
575ffd83dbSDimitry Andric     while (!getLexer().is(AsmToken::EndOfStatement)) {
585ffd83dbSDimitry Andric       Lex();
595ffd83dbSDimitry Andric     }
605ffd83dbSDimitry Andric     return false;
615ffd83dbSDimitry Andric   }
625ffd83dbSDimitry Andric 
635ffd83dbSDimitry Andric   void Initialize(MCAsmParser &Parser) override {
645ffd83dbSDimitry Andric     // Call the base implementation.
655ffd83dbSDimitry Andric     MCAsmParserExtension::Initialize(Parser);
665ffd83dbSDimitry Andric 
675ffd83dbSDimitry Andric     // x64 directives
68e8d8bef9SDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
69e8d8bef9SDimitry Andric         ".allocstack");
70e8d8bef9SDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
71e8d8bef9SDimitry Andric         ".endprolog");
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric     // Code label directives
745ffd83dbSDimitry Andric     // label
755ffd83dbSDimitry Andric     // org
765ffd83dbSDimitry Andric 
775ffd83dbSDimitry Andric     // Conditional control flow directives
785ffd83dbSDimitry Andric     // .break
795ffd83dbSDimitry Andric     // .continue
805ffd83dbSDimitry Andric     // .else
815ffd83dbSDimitry Andric     // .elseif
825ffd83dbSDimitry Andric     // .endif
835ffd83dbSDimitry Andric     // .endw
845ffd83dbSDimitry Andric     // .if
855ffd83dbSDimitry Andric     // .repeat
865ffd83dbSDimitry Andric     // .until
875ffd83dbSDimitry Andric     // .untilcxz
885ffd83dbSDimitry Andric     // .while
895ffd83dbSDimitry Andric 
905ffd83dbSDimitry Andric     // Data allocation directives
915ffd83dbSDimitry Andric     // align
925ffd83dbSDimitry Andric     // even
93e8d8bef9SDimitry Andric     // mmword
945ffd83dbSDimitry Andric     // tbyte
95e8d8bef9SDimitry Andric     // xmmword
96e8d8bef9SDimitry Andric     // ymmword
975ffd83dbSDimitry Andric 
985ffd83dbSDimitry Andric     // Listing control directives
995ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
1005ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
1015ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
1025ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
1035ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
1045ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
1055ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
1065ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
1075ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
1085ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
1095ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
1105ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
1115ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
1125ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
1135ffd83dbSDimitry Andric 
1145ffd83dbSDimitry Andric     // Macro directives
1155ffd83dbSDimitry Andric     // goto
1165ffd83dbSDimitry Andric 
1175ffd83dbSDimitry Andric     // Miscellaneous directives
118e8d8bef9SDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
1195ffd83dbSDimitry Andric     // assume
1205ffd83dbSDimitry Andric     // .fpo
1215ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
1225ffd83dbSDimitry Andric         "includelib");
123bdd1243dSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveOption>("option");
1245ffd83dbSDimitry Andric     // popcontext
1255ffd83dbSDimitry Andric     // pushcontext
1265ffd83dbSDimitry Andric     // .safeseh
1275ffd83dbSDimitry Andric 
1285ffd83dbSDimitry Andric     // Procedure directives
1295ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
1305ffd83dbSDimitry Andric     // invoke (32-bit only)
1315ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
1325ffd83dbSDimitry Andric     // proto
1335ffd83dbSDimitry Andric 
134e8d8bef9SDimitry Andric     // Processor directives; all ignored
1355ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
136fe6060f1SDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386p");
1375ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
1385ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
139fe6060f1SDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486p");
1405ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
141fe6060f1SDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586p");
1425ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
143fe6060f1SDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686p");
1445ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
1455ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
1465ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
1475ffd83dbSDimitry Andric 
1485ffd83dbSDimitry Andric     // Scope directives
1495ffd83dbSDimitry Andric     // comm
1505ffd83dbSDimitry Andric     // externdef
1515ffd83dbSDimitry Andric 
1525ffd83dbSDimitry Andric     // Segment directives
1535ffd83dbSDimitry Andric     // .alpha (32-bit only, order segments alphabetically)
1545ffd83dbSDimitry Andric     // .dosseg (32-bit only, order segments in DOS convention)
1555ffd83dbSDimitry Andric     // .seq (32-bit only, order segments sequentially)
1565ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
1575ffd83dbSDimitry Andric     // group (32-bit only)
1585ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
1595ffd83dbSDimitry Andric 
1605ffd83dbSDimitry Andric     // Simplified segment directives
1615ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
1625ffd83dbSDimitry Andric     // .const
1635ffd83dbSDimitry Andric     addDirectiveHandler<
1645ffd83dbSDimitry Andric         &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
1655ffd83dbSDimitry Andric     addDirectiveHandler<
1665ffd83dbSDimitry Andric         &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
1675ffd83dbSDimitry Andric     // .exit
1685ffd83dbSDimitry Andric     // .fardata
1695ffd83dbSDimitry Andric     // .fardata?
1705ffd83dbSDimitry Andric     addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
1715ffd83dbSDimitry Andric     // .stack
1725ffd83dbSDimitry Andric     // .startup
1735ffd83dbSDimitry Andric 
1745ffd83dbSDimitry Andric     // String directives, written <name> <directive> <params>
1755ffd83dbSDimitry Andric     // catstr (equivalent to <name> TEXTEQU <params>)
1765ffd83dbSDimitry Andric     // instr (equivalent to <name> = @InStr(<params>))
1775ffd83dbSDimitry Andric     // sizestr (equivalent to <name> = @SizeStr(<params>))
1785ffd83dbSDimitry Andric     // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
1795ffd83dbSDimitry Andric 
1805ffd83dbSDimitry Andric     // Structure and record directives
1815ffd83dbSDimitry Andric     // record
1825ffd83dbSDimitry Andric     // typedef
1835ffd83dbSDimitry Andric   }
1845ffd83dbSDimitry Andric 
1855ffd83dbSDimitry Andric   bool ParseSectionDirectiveCode(StringRef, SMLoc) {
186*0fca6ea1SDimitry Andric     return ParseSectionSwitch(".text", COFF::IMAGE_SCN_CNT_CODE |
187*0fca6ea1SDimitry Andric                                            COFF::IMAGE_SCN_MEM_EXECUTE |
188*0fca6ea1SDimitry Andric                                            COFF::IMAGE_SCN_MEM_READ);
1895ffd83dbSDimitry Andric   }
1905ffd83dbSDimitry Andric 
1915ffd83dbSDimitry Andric   bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
192*0fca6ea1SDimitry Andric     return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
193*0fca6ea1SDimitry Andric                                            COFF::IMAGE_SCN_MEM_READ |
194*0fca6ea1SDimitry Andric                                            COFF::IMAGE_SCN_MEM_WRITE);
1955ffd83dbSDimitry Andric   }
1965ffd83dbSDimitry Andric 
1975ffd83dbSDimitry Andric   bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
198*0fca6ea1SDimitry Andric     return ParseSectionSwitch(".bss", COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
199*0fca6ea1SDimitry Andric                                           COFF::IMAGE_SCN_MEM_READ |
200*0fca6ea1SDimitry Andric                                           COFF::IMAGE_SCN_MEM_WRITE);
2015ffd83dbSDimitry Andric   }
2025ffd83dbSDimitry Andric 
203bdd1243dSDimitry Andric   /// Stack of active procedure definitions.
204bdd1243dSDimitry Andric   SmallVector<StringRef, 1> CurrentProcedures;
205bdd1243dSDimitry Andric   SmallVector<bool, 1> CurrentProceduresFramed;
2065ffd83dbSDimitry Andric 
2075ffd83dbSDimitry Andric public:
2085ffd83dbSDimitry Andric   COFFMasmParser() = default;
2095ffd83dbSDimitry Andric };
2105ffd83dbSDimitry Andric 
2115ffd83dbSDimitry Andric } // end anonymous namespace.
2125ffd83dbSDimitry Andric 
213bdd1243dSDimitry Andric bool COFFMasmParser::ParseSectionSwitch(StringRef SectionName,
214*0fca6ea1SDimitry Andric                                         unsigned Characteristics) {
215*0fca6ea1SDimitry Andric   return ParseSectionSwitch(SectionName, Characteristics, "",
216bdd1243dSDimitry Andric                             (COFF::COMDATType)0, Align(16));
2175ffd83dbSDimitry Andric }
2185ffd83dbSDimitry Andric 
219*0fca6ea1SDimitry Andric bool COFFMasmParser::ParseSectionSwitch(StringRef SectionName,
220*0fca6ea1SDimitry Andric                                         unsigned Characteristics,
221*0fca6ea1SDimitry Andric                                         StringRef COMDATSymName,
222*0fca6ea1SDimitry Andric                                         COFF::COMDATType Type,
223*0fca6ea1SDimitry Andric                                         Align Alignment) {
2245ffd83dbSDimitry Andric   if (getLexer().isNot(AsmToken::EndOfStatement))
2255ffd83dbSDimitry Andric     return TokError("unexpected token in section switching directive");
2265ffd83dbSDimitry Andric   Lex();
2275ffd83dbSDimitry Andric 
228bdd1243dSDimitry Andric   MCSection *Section = getContext().getCOFFSection(SectionName, Characteristics,
229*0fca6ea1SDimitry Andric                                                    COMDATSymName, Type);
230bdd1243dSDimitry Andric   Section->setAlignment(Alignment);
231bdd1243dSDimitry Andric   getStreamer().switchSection(Section);
2325ffd83dbSDimitry Andric 
2335ffd83dbSDimitry Andric   return false;
2345ffd83dbSDimitry Andric }
2355ffd83dbSDimitry Andric 
2365ffd83dbSDimitry Andric bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
2375ffd83dbSDimitry Andric   StringRef SegmentName;
2385ffd83dbSDimitry Andric   if (!getLexer().is(AsmToken::Identifier))
2395ffd83dbSDimitry Andric     return TokError("expected identifier in directive");
2405ffd83dbSDimitry Andric   SegmentName = getTok().getIdentifier();
2415ffd83dbSDimitry Andric   Lex();
2425ffd83dbSDimitry Andric 
2435ffd83dbSDimitry Andric   StringRef SectionName = SegmentName;
2445ffd83dbSDimitry Andric   SmallVector<char, 247> SectionNameVector;
245bdd1243dSDimitry Andric 
246bdd1243dSDimitry Andric   StringRef Class;
2475f757f3fSDimitry Andric   if (SegmentName == "_TEXT" || SegmentName.starts_with("_TEXT$")) {
2485ffd83dbSDimitry Andric     if (SegmentName.size() == 5) {
2495ffd83dbSDimitry Andric       SectionName = ".text";
2505ffd83dbSDimitry Andric     } else {
2515ffd83dbSDimitry Andric       SectionName =
2525ffd83dbSDimitry Andric           (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
2535ffd83dbSDimitry Andric     }
254bdd1243dSDimitry Andric     Class = "CODE";
2555ffd83dbSDimitry Andric   }
256bdd1243dSDimitry Andric 
257bdd1243dSDimitry Andric   // Parse all options to end of statement.
258bdd1243dSDimitry Andric   // Alignment defaults to PARA if unspecified.
259bdd1243dSDimitry Andric   int64_t Alignment = 16;
260bdd1243dSDimitry Andric   // Default flags are used only if no characteristics are set.
261bdd1243dSDimitry Andric   bool DefaultCharacteristics = true;
262bdd1243dSDimitry Andric   unsigned Flags = 0;
263bdd1243dSDimitry Andric   // "obsolete" according to the documentation, but still supported.
264bdd1243dSDimitry Andric   bool Readonly = false;
265bdd1243dSDimitry Andric   while (getLexer().isNot(AsmToken::EndOfStatement)) {
266bdd1243dSDimitry Andric     switch (getTok().getKind()) {
267bdd1243dSDimitry Andric     default:
268bdd1243dSDimitry Andric       break;
269bdd1243dSDimitry Andric     case AsmToken::String: {
270bdd1243dSDimitry Andric       // Class identifier; overrides Kind.
271bdd1243dSDimitry Andric       Class = getTok().getStringContents();
272bdd1243dSDimitry Andric       Lex();
273bdd1243dSDimitry Andric       break;
274bdd1243dSDimitry Andric     }
275bdd1243dSDimitry Andric     case AsmToken::Identifier: {
276bdd1243dSDimitry Andric       SMLoc KeywordLoc = getTok().getLoc();
277bdd1243dSDimitry Andric       StringRef Keyword;
278bdd1243dSDimitry Andric       if (getParser().parseIdentifier(Keyword)) {
279bdd1243dSDimitry Andric         llvm_unreachable("failed to parse identifier at an identifier token");
280bdd1243dSDimitry Andric       }
281bdd1243dSDimitry Andric       if (Keyword.equals_insensitive("byte")) {
282bdd1243dSDimitry Andric         Alignment = 1;
283bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("word")) {
284bdd1243dSDimitry Andric         Alignment = 2;
285bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("dword")) {
286bdd1243dSDimitry Andric         Alignment = 4;
287bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("para")) {
288bdd1243dSDimitry Andric         Alignment = 16;
289bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("page")) {
290bdd1243dSDimitry Andric         Alignment = 256;
291bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("align")) {
292bdd1243dSDimitry Andric         if (getParser().parseToken(AsmToken::LParen) ||
293bdd1243dSDimitry Andric             getParser().parseIntToken(Alignment,
294bdd1243dSDimitry Andric                                       "Expected integer alignment") ||
295bdd1243dSDimitry Andric             getParser().parseToken(AsmToken::RParen)) {
296bdd1243dSDimitry Andric           return Error(getTok().getLoc(),
297bdd1243dSDimitry Andric                        "Expected (n) following ALIGN in SEGMENT directive");
298bdd1243dSDimitry Andric         }
299bdd1243dSDimitry Andric         if (!isPowerOf2_64(Alignment) || Alignment > 8192) {
300bdd1243dSDimitry Andric           return Error(KeywordLoc,
301bdd1243dSDimitry Andric                        "ALIGN argument must be a power of 2 from 1 to 8192");
302bdd1243dSDimitry Andric         }
303bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("alias")) {
304bdd1243dSDimitry Andric         if (getParser().parseToken(AsmToken::LParen) ||
305bdd1243dSDimitry Andric             !getTok().is(AsmToken::String))
306bdd1243dSDimitry Andric           return Error(
307bdd1243dSDimitry Andric               getTok().getLoc(),
308bdd1243dSDimitry Andric               "Expected (string) following ALIAS in SEGMENT directive");
309bdd1243dSDimitry Andric         SectionName = getTok().getStringContents();
310bdd1243dSDimitry Andric         Lex();
311bdd1243dSDimitry Andric         if (getParser().parseToken(AsmToken::RParen))
312bdd1243dSDimitry Andric           return Error(
313bdd1243dSDimitry Andric               getTok().getLoc(),
314bdd1243dSDimitry Andric               "Expected (string) following ALIAS in SEGMENT directive");
315bdd1243dSDimitry Andric       } else if (Keyword.equals_insensitive("readonly")) {
316bdd1243dSDimitry Andric         Readonly = true;
317bdd1243dSDimitry Andric       } else {
318bdd1243dSDimitry Andric         unsigned Characteristic =
319bdd1243dSDimitry Andric             StringSwitch<unsigned>(Keyword)
320bdd1243dSDimitry Andric                 .CaseLower("info", COFF::IMAGE_SCN_LNK_INFO)
321bdd1243dSDimitry Andric                 .CaseLower("read", COFF::IMAGE_SCN_MEM_READ)
322bdd1243dSDimitry Andric                 .CaseLower("write", COFF::IMAGE_SCN_MEM_WRITE)
323bdd1243dSDimitry Andric                 .CaseLower("execute", COFF::IMAGE_SCN_MEM_EXECUTE)
324bdd1243dSDimitry Andric                 .CaseLower("shared", COFF::IMAGE_SCN_MEM_SHARED)
325bdd1243dSDimitry Andric                 .CaseLower("nopage", COFF::IMAGE_SCN_MEM_NOT_PAGED)
326bdd1243dSDimitry Andric                 .CaseLower("nocache", COFF::IMAGE_SCN_MEM_NOT_CACHED)
327bdd1243dSDimitry Andric                 .CaseLower("discard", COFF::IMAGE_SCN_MEM_DISCARDABLE)
328bdd1243dSDimitry Andric                 .Default(-1);
329bdd1243dSDimitry Andric         if (Characteristic == static_cast<unsigned>(-1)) {
330bdd1243dSDimitry Andric           return Error(KeywordLoc,
331bdd1243dSDimitry Andric                        "Expected characteristic in SEGMENT directive; found '" +
332bdd1243dSDimitry Andric                            Keyword + "'");
333bdd1243dSDimitry Andric         }
334bdd1243dSDimitry Andric         Flags |= Characteristic;
335bdd1243dSDimitry Andric         DefaultCharacteristics = false;
336bdd1243dSDimitry Andric       }
337bdd1243dSDimitry Andric     }
338bdd1243dSDimitry Andric     }
339bdd1243dSDimitry Andric   }
340bdd1243dSDimitry Andric 
341bdd1243dSDimitry Andric   SectionKind Kind = StringSwitch<SectionKind>(Class)
342bdd1243dSDimitry Andric                          .CaseLower("data", SectionKind::getData())
343bdd1243dSDimitry Andric                          .CaseLower("code", SectionKind::getText())
344bdd1243dSDimitry Andric                          .CaseLower("const", SectionKind::getReadOnly())
345bdd1243dSDimitry Andric                          .Default(SectionKind::getData());
346bdd1243dSDimitry Andric   if (Kind.isText()) {
347bdd1243dSDimitry Andric     if (DefaultCharacteristics) {
348bdd1243dSDimitry Andric       Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ;
349bdd1243dSDimitry Andric     }
350bdd1243dSDimitry Andric     Flags |= COFF::IMAGE_SCN_CNT_CODE;
351bdd1243dSDimitry Andric   } else {
352bdd1243dSDimitry Andric     if (DefaultCharacteristics) {
353bdd1243dSDimitry Andric       Flags |= COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
354bdd1243dSDimitry Andric     }
355bdd1243dSDimitry Andric     Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
356bdd1243dSDimitry Andric   }
357bdd1243dSDimitry Andric   if (Readonly) {
358bdd1243dSDimitry Andric     Flags &= ~COFF::IMAGE_SCN_MEM_WRITE;
359bdd1243dSDimitry Andric   }
360bdd1243dSDimitry Andric 
361*0fca6ea1SDimitry Andric   MCSection *Section = getContext().getCOFFSection(SectionName, Flags, "",
362bdd1243dSDimitry Andric                                                    (COFF::COMDATType)(0));
363bdd1243dSDimitry Andric   if (Alignment != 0) {
364bdd1243dSDimitry Andric     Section->setAlignment(Align(Alignment));
365bdd1243dSDimitry Andric   }
366bdd1243dSDimitry Andric   getStreamer().switchSection(Section);
3675ffd83dbSDimitry Andric   return false;
3685ffd83dbSDimitry Andric }
3695ffd83dbSDimitry Andric 
3705ffd83dbSDimitry Andric /// ParseDirectiveSegmentEnd
3715ffd83dbSDimitry Andric ///  ::= identifier "ends"
3725ffd83dbSDimitry Andric bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
3735ffd83dbSDimitry Andric   StringRef SegmentName;
3745ffd83dbSDimitry Andric   if (!getLexer().is(AsmToken::Identifier))
3755ffd83dbSDimitry Andric     return TokError("expected identifier in directive");
3765ffd83dbSDimitry Andric   SegmentName = getTok().getIdentifier();
3775ffd83dbSDimitry Andric 
3785ffd83dbSDimitry Andric   // Ignore; no action necessary.
3795ffd83dbSDimitry Andric   Lex();
3805ffd83dbSDimitry Andric   return false;
3815ffd83dbSDimitry Andric }
3825ffd83dbSDimitry Andric 
3835ffd83dbSDimitry Andric /// ParseDirectiveIncludelib
3845ffd83dbSDimitry Andric ///  ::= "includelib" identifier
3855ffd83dbSDimitry Andric bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
3865ffd83dbSDimitry Andric   StringRef Lib;
3875ffd83dbSDimitry Andric   if (getParser().parseIdentifier(Lib))
3885ffd83dbSDimitry Andric     return TokError("expected identifier in includelib directive");
3895ffd83dbSDimitry Andric 
3905ffd83dbSDimitry Andric   unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
39181ad6265SDimitry Andric   getStreamer().pushSection();
39281ad6265SDimitry Andric   getStreamer().switchSection(getContext().getCOFFSection(
393*0fca6ea1SDimitry Andric       ".drectve", Flags, "", (COFF::COMDATType)(0)));
3945ffd83dbSDimitry Andric   getStreamer().emitBytes("/DEFAULTLIB:");
3955ffd83dbSDimitry Andric   getStreamer().emitBytes(Lib);
3965ffd83dbSDimitry Andric   getStreamer().emitBytes(" ");
39781ad6265SDimitry Andric   getStreamer().popSection();
3985ffd83dbSDimitry Andric   return false;
3995ffd83dbSDimitry Andric }
4005ffd83dbSDimitry Andric 
401bdd1243dSDimitry Andric /// ParseDirectiveOption
402bdd1243dSDimitry Andric ///  ::= "option" option-list
403bdd1243dSDimitry Andric bool COFFMasmParser::ParseDirectiveOption(StringRef Directive, SMLoc Loc) {
404bdd1243dSDimitry Andric   auto parseOption = [&]() -> bool {
405bdd1243dSDimitry Andric     StringRef Option;
406bdd1243dSDimitry Andric     if (getParser().parseIdentifier(Option))
407bdd1243dSDimitry Andric       return TokError("expected identifier for option name");
408bdd1243dSDimitry Andric     if (Option.equals_insensitive("prologue")) {
409bdd1243dSDimitry Andric       StringRef MacroId;
410bdd1243dSDimitry Andric       if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
411bdd1243dSDimitry Andric         return TokError("expected :macroId after OPTION PROLOGUE");
412bdd1243dSDimitry Andric       if (MacroId.equals_insensitive("none")) {
413bdd1243dSDimitry Andric         // Since we currently don't implement prologues/epilogues, NONE is our
414bdd1243dSDimitry Andric         // default.
415bdd1243dSDimitry Andric         return false;
416bdd1243dSDimitry Andric       }
417bdd1243dSDimitry Andric       return TokError("OPTION PROLOGUE is currently unsupported");
418bdd1243dSDimitry Andric     }
419bdd1243dSDimitry Andric     if (Option.equals_insensitive("epilogue")) {
420bdd1243dSDimitry Andric       StringRef MacroId;
421bdd1243dSDimitry Andric       if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
422bdd1243dSDimitry Andric         return TokError("expected :macroId after OPTION EPILOGUE");
423bdd1243dSDimitry Andric       if (MacroId.equals_insensitive("none")) {
424bdd1243dSDimitry Andric         // Since we currently don't implement prologues/epilogues, NONE is our
425bdd1243dSDimitry Andric         // default.
426bdd1243dSDimitry Andric         return false;
427bdd1243dSDimitry Andric       }
428bdd1243dSDimitry Andric       return TokError("OPTION EPILOGUE is currently unsupported");
429bdd1243dSDimitry Andric     }
430bdd1243dSDimitry Andric     return TokError("OPTION '" + Option + "' is currently unsupported");
431bdd1243dSDimitry Andric   };
432bdd1243dSDimitry Andric 
433bdd1243dSDimitry Andric   if (parseMany(parseOption))
434bdd1243dSDimitry Andric     return addErrorSuffix(" in OPTION directive");
435bdd1243dSDimitry Andric   return false;
436bdd1243dSDimitry Andric }
437bdd1243dSDimitry Andric 
4385ffd83dbSDimitry Andric /// ParseDirectiveProc
4395ffd83dbSDimitry Andric /// TODO(epastor): Implement parameters and other attributes.
4405ffd83dbSDimitry Andric ///  ::= label "proc" [[distance]]
4415ffd83dbSDimitry Andric ///          statements
4425ffd83dbSDimitry Andric ///      label "endproc"
4435ffd83dbSDimitry Andric bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
4445ffd83dbSDimitry Andric   StringRef Label;
4455ffd83dbSDimitry Andric   if (getParser().parseIdentifier(Label))
4465ffd83dbSDimitry Andric     return Error(Loc, "expected identifier for procedure");
4475ffd83dbSDimitry Andric   if (getLexer().is(AsmToken::Identifier)) {
4485ffd83dbSDimitry Andric     StringRef nextVal = getTok().getString();
4495ffd83dbSDimitry Andric     SMLoc nextLoc = getTok().getLoc();
450fe6060f1SDimitry Andric     if (nextVal.equals_insensitive("far")) {
4515ffd83dbSDimitry Andric       // TODO(epastor): Handle far procedure definitions.
4525ffd83dbSDimitry Andric       Lex();
4535ffd83dbSDimitry Andric       return Error(nextLoc, "far procedure definitions not yet supported");
454fe6060f1SDimitry Andric     } else if (nextVal.equals_insensitive("near")) {
4555ffd83dbSDimitry Andric       Lex();
4565ffd83dbSDimitry Andric       nextVal = getTok().getString();
4575ffd83dbSDimitry Andric       nextLoc = getTok().getLoc();
4585ffd83dbSDimitry Andric     }
4595ffd83dbSDimitry Andric   }
460e8d8bef9SDimitry Andric   MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
4615ffd83dbSDimitry Andric 
462e8d8bef9SDimitry Andric   // Define symbol as simple external function
463e8d8bef9SDimitry Andric   Sym->setExternal(true);
464e8d8bef9SDimitry Andric   Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
4655ffd83dbSDimitry Andric 
466e8d8bef9SDimitry Andric   bool Framed = false;
467e8d8bef9SDimitry Andric   if (getLexer().is(AsmToken::Identifier) &&
468fe6060f1SDimitry Andric       getTok().getString().equals_insensitive("frame")) {
469e8d8bef9SDimitry Andric     Lex();
470e8d8bef9SDimitry Andric     Framed = true;
47181ad6265SDimitry Andric     getStreamer().emitWinCFIStartProc(Sym, Loc);
472e8d8bef9SDimitry Andric   }
4735ffd83dbSDimitry Andric   getStreamer().emitLabel(Sym, Loc);
474e8d8bef9SDimitry Andric 
475bdd1243dSDimitry Andric   CurrentProcedures.push_back(Label);
476bdd1243dSDimitry Andric   CurrentProceduresFramed.push_back(Framed);
4775ffd83dbSDimitry Andric   return false;
4785ffd83dbSDimitry Andric }
4795ffd83dbSDimitry Andric bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
4805ffd83dbSDimitry Andric   StringRef Label;
4815ffd83dbSDimitry Andric   SMLoc LabelLoc = getTok().getLoc();
4825ffd83dbSDimitry Andric   if (getParser().parseIdentifier(Label))
4835ffd83dbSDimitry Andric     return Error(LabelLoc, "expected identifier for procedure end");
4845ffd83dbSDimitry Andric 
485bdd1243dSDimitry Andric   if (CurrentProcedures.empty())
4865ffd83dbSDimitry Andric     return Error(Loc, "endp outside of procedure block");
487bdd1243dSDimitry Andric   else if (!CurrentProcedures.back().equals_insensitive(Label))
4885ffd83dbSDimitry Andric     return Error(LabelLoc, "endp does not match current procedure '" +
489bdd1243dSDimitry Andric                                CurrentProcedures.back() + "'");
490e8d8bef9SDimitry Andric 
491bdd1243dSDimitry Andric   if (CurrentProceduresFramed.back()) {
49281ad6265SDimitry Andric     getStreamer().emitWinCFIEndProc(Loc);
493e8d8bef9SDimitry Andric   }
494bdd1243dSDimitry Andric   CurrentProcedures.pop_back();
495bdd1243dSDimitry Andric   CurrentProceduresFramed.pop_back();
496e8d8bef9SDimitry Andric   return false;
497e8d8bef9SDimitry Andric }
498e8d8bef9SDimitry Andric 
499e8d8bef9SDimitry Andric bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
500e8d8bef9SDimitry Andric   std::string AliasName, ActualName;
501e8d8bef9SDimitry Andric   if (getTok().isNot(AsmToken::Less) ||
502e8d8bef9SDimitry Andric       getParser().parseAngleBracketString(AliasName))
503e8d8bef9SDimitry Andric     return Error(getTok().getLoc(), "expected <aliasName>");
504e8d8bef9SDimitry Andric   if (getParser().parseToken(AsmToken::Equal))
505e8d8bef9SDimitry Andric     return addErrorSuffix(" in " + Directive + " directive");
506e8d8bef9SDimitry Andric   if (getTok().isNot(AsmToken::Less) ||
507e8d8bef9SDimitry Andric       getParser().parseAngleBracketString(ActualName))
508e8d8bef9SDimitry Andric     return Error(getTok().getLoc(), "expected <actualName>");
509e8d8bef9SDimitry Andric 
510e8d8bef9SDimitry Andric   MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
511e8d8bef9SDimitry Andric   MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
512e8d8bef9SDimitry Andric 
513e8d8bef9SDimitry Andric   getStreamer().emitWeakReference(Alias, Actual);
514e8d8bef9SDimitry Andric 
515e8d8bef9SDimitry Andric   return false;
516e8d8bef9SDimitry Andric }
517e8d8bef9SDimitry Andric 
518e8d8bef9SDimitry Andric bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
519e8d8bef9SDimitry Andric                                                  SMLoc Loc) {
520e8d8bef9SDimitry Andric   int64_t Size;
521e8d8bef9SDimitry Andric   SMLoc SizeLoc = getTok().getLoc();
522e8d8bef9SDimitry Andric   if (getParser().parseAbsoluteExpression(Size))
523e8d8bef9SDimitry Andric     return Error(SizeLoc, "expected integer size");
524e8d8bef9SDimitry Andric   if (Size % 8 != 0)
525e8d8bef9SDimitry Andric     return Error(SizeLoc, "stack size must be a multiple of 8");
52681ad6265SDimitry Andric   getStreamer().emitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
527e8d8bef9SDimitry Andric   return false;
528e8d8bef9SDimitry Andric }
529e8d8bef9SDimitry Andric 
530e8d8bef9SDimitry Andric bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
531e8d8bef9SDimitry Andric                                                 SMLoc Loc) {
53281ad6265SDimitry Andric   getStreamer().emitWinCFIEndProlog(Loc);
5335ffd83dbSDimitry Andric   return false;
5345ffd83dbSDimitry Andric }
5355ffd83dbSDimitry Andric 
5365ffd83dbSDimitry Andric namespace llvm {
5375ffd83dbSDimitry Andric 
5385ffd83dbSDimitry Andric MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
5395ffd83dbSDimitry Andric 
5405ffd83dbSDimitry Andric } // end namespace llvm
541