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