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)>
addDirectiveHandler(StringRef Directive)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
IgnoreDirective(StringRef,SMLoc)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
Initialize(MCAsmParser & Parser)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
ParseSectionDirectiveCode(StringRef,SMLoc)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
ParseSectionDirectiveInitializedData(StringRef,SMLoc)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
ParseSectionDirectiveUninitializedData(StringRef,SMLoc)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
ParseSectionSwitch(StringRef SectionName,unsigned Characteristics)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
ParseSectionSwitch(StringRef SectionName,unsigned Characteristics,StringRef COMDATSymName,COFF::COMDATType Type,Align Alignment)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
ParseDirectiveSegment(StringRef Directive,SMLoc Loc)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"
ParseDirectiveSegmentEnd(StringRef Directive,SMLoc Loc)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
ParseDirectiveIncludelib(StringRef Directive,SMLoc Loc)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
ParseDirectiveOption(StringRef Directive,SMLoc Loc)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"
ParseDirectiveProc(StringRef Directive,SMLoc Loc)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 }
ParseDirectiveEndProc(StringRef Directive,SMLoc Loc)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
ParseDirectiveAlias(StringRef Directive,SMLoc Loc)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
ParseSEHDirectiveAllocStack(StringRef Directive,SMLoc Loc)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
ParseSEHDirectiveEndProlog(StringRef Directive,SMLoc Loc)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
createCOFFMasmParser()5385ffd83dbSDimitry Andric MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
5395ffd83dbSDimitry Andric
5405ffd83dbSDimitry Andric } // end namespace llvm
541