summaryrefslogtreecommitdiff
path: root/llvm/lib/MC/MCParser/COFFMasmParser.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-26 19:36:28 +0000
commitcfca06d7963fa0909f90483b42a6d7d194d01e08 (patch)
tree209fb2a2d68f8f277793fc8df46c753d31bc853b /llvm/lib/MC/MCParser/COFFMasmParser.cpp
parent706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff)
Notes
Diffstat (limited to 'llvm/lib/MC/MCParser/COFFMasmParser.cpp')
-rw-r--r--llvm/lib/MC/MCParser/COFFMasmParser.cpp386
1 files changed, 386 insertions, 0 deletions
diff --git a/llvm/lib/MC/MCParser/COFFMasmParser.cpp b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
new file mode 100644
index 0000000000000..b7c48e92961b3
--- /dev/null
+++ b/llvm/lib/MC/MCParser/COFFMasmParser.cpp
@@ -0,0 +1,386 @@
+//===- COFFMasmParser.cpp - COFF MASM Assembly Parser ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCAsmParserUtils.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+#include <cstdint>
+#include <limits>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+
+class COFFMasmParser : public MCAsmParserExtension {
+ template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
+ void addDirectiveHandler(StringRef Directive) {
+ MCAsmParser::ExtensionDirectiveHandler Handler =
+ std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
+ getParser().addDirectiveHandler(Directive, Handler);
+ }
+
+ bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
+ SectionKind Kind);
+
+ bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
+ SectionKind Kind, StringRef COMDATSymName,
+ COFF::COMDATType Type);
+
+ bool ParseDirectiveProc(StringRef, SMLoc);
+ bool ParseDirectiveEndProc(StringRef, SMLoc);
+ bool ParseDirectiveSegment(StringRef, SMLoc);
+ bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
+ bool ParseDirectiveIncludelib(StringRef, SMLoc);
+
+ bool IgnoreDirective(StringRef, SMLoc) {
+ while (!getLexer().is(AsmToken::EndOfStatement)) {
+ Lex();
+ }
+ return false;
+ }
+
+ void Initialize(MCAsmParser &Parser) override {
+ // Call the base implementation.
+ MCAsmParserExtension::Initialize(Parser);
+
+ // x64 directives
+ // .allocstack
+ // .endprolog
+ // .pushframe
+ // .pushreg
+ // .savereg
+ // .savexmm128
+ // .setframe
+
+ // Code label directives
+ // label
+ // org
+
+ // Conditional control flow directives
+ // .break
+ // .continue
+ // .else
+ // .elseif
+ // .endif
+ // .endw
+ // .if
+ // .repeat
+ // .until
+ // .untilcxz
+ // .while
+
+ // Data allocation directives
+ // align
+ // byte/sbyte
+ // dword/sdword
+ // even
+ // fword
+ // qword
+ // real4
+ // real8
+ // real10
+ // tbyte
+ // word/sword
+
+ // Listing control directives
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
+
+ // Macro directives
+ // endm
+ // exitm
+ // goto
+ // local
+ // macro
+ // purge
+
+ // Miscellaneous directives
+ // alias
+ // assume
+ // .fpo
+ addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
+ "includelib");
+ // mmword
+ // option
+ // popcontext
+ // pushcontext
+ // .radix
+ // .safeseh
+ // xmmword
+ // ymmword
+
+ // Procedure directives
+ addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
+ // invoke (32-bit only)
+ addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
+ // proto
+
+ // Processor directives
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386P");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486P");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586P");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686P");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
+
+ // Repeat blocks directives
+ // for
+ // forc
+ // goto
+ // repeat
+ // while
+
+ // Scope directives
+ // comm
+ // externdef
+
+ // Segment directives
+ // .alpha (32-bit only, order segments alphabetically)
+ // .dosseg (32-bit only, order segments in DOS convention)
+ // .seq (32-bit only, order segments sequentially)
+ addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
+ // group (32-bit only)
+ addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
+
+ // Simplified segment directives
+ addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
+ // .const
+ addDirectiveHandler<
+ &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
+ addDirectiveHandler<
+ &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
+ // .exit
+ // .fardata
+ // .fardata?
+ addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
+ // .stack
+ // .startup
+
+ // String directives, written <name> <directive> <params>
+ // catstr (equivalent to <name> TEXTEQU <params>)
+ // instr (equivalent to <name> = @InStr(<params>))
+ // sizestr (equivalent to <name> = @SizeStr(<params>))
+ // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
+
+ // Structure and record directives
+ // ends
+ // record
+ // struct
+ // typedef
+ // union
+ }
+
+ bool ParseSectionDirectiveCode(StringRef, SMLoc) {
+ return ParseSectionSwitch(".text",
+ COFF::IMAGE_SCN_CNT_CODE
+ | COFF::IMAGE_SCN_MEM_EXECUTE
+ | COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getText());
+ }
+
+ bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".data",
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
+ | COFF::IMAGE_SCN_MEM_READ
+ | COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getData());
+ }
+
+ bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".bss",
+ COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ | COFF::IMAGE_SCN_MEM_READ
+ | COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getBSS());
+ }
+
+ StringRef CurrentProcedure;
+
+public:
+ COFFMasmParser() = default;
+};
+
+} // end anonymous namespace.
+
+static SectionKind computeSectionKind(unsigned Flags) {
+ if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
+ return SectionKind::getText();
+ if (Flags & COFF::IMAGE_SCN_MEM_READ &&
+ (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
+ return SectionKind::getReadOnly();
+ return SectionKind::getData();
+}
+
+bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind) {
+ return ParseSectionSwitch(Section, Characteristics, Kind, "",
+ (COFF::COMDATType)0);
+}
+
+bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind,
+ StringRef COMDATSymName,
+ COFF::COMDATType Type) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in section switching directive");
+ Lex();
+
+ getStreamer().SwitchSection(getContext().getCOFFSection(
+ Section, Characteristics, Kind, COMDATSymName, Type));
+
+ return false;
+}
+
+bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
+ StringRef SegmentName;
+ if (!getLexer().is(AsmToken::Identifier))
+ return TokError("expected identifier in directive");
+ SegmentName = getTok().getIdentifier();
+ Lex();
+
+ StringRef SectionName = SegmentName;
+ SmallVector<char, 247> SectionNameVector;
+ unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
+ if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
+ if (SegmentName.size() == 5) {
+ SectionName = ".text";
+ } else {
+ SectionName =
+ (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
+ }
+ Flags = COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE |
+ COFF::IMAGE_SCN_MEM_READ;
+ }
+ SectionKind Kind = computeSectionKind(Flags);
+ getStreamer().SwitchSection(getContext().getCOFFSection(
+ SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
+ return false;
+}
+
+/// ParseDirectiveSegmentEnd
+/// ::= identifier "ends"
+bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
+ StringRef SegmentName;
+ if (!getLexer().is(AsmToken::Identifier))
+ return TokError("expected identifier in directive");
+ SegmentName = getTok().getIdentifier();
+
+ // Ignore; no action necessary.
+ Lex();
+ return false;
+}
+
+/// ParseDirectiveIncludelib
+/// ::= "includelib" identifier
+bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
+ StringRef Lib;
+ if (getParser().parseIdentifier(Lib))
+ return TokError("expected identifier in includelib directive");
+
+ unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
+ SectionKind Kind = computeSectionKind(Flags);
+ getStreamer().PushSection();
+ getStreamer().SwitchSection(getContext().getCOFFSection(
+ ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
+ getStreamer().emitBytes("/DEFAULTLIB:");
+ getStreamer().emitBytes(Lib);
+ getStreamer().emitBytes(" ");
+ getStreamer().PopSection();
+ return false;
+}
+
+/// ParseDirectiveProc
+/// TODO(epastor): Implement parameters and other attributes.
+/// ::= label "proc" [[distance]]
+/// statements
+/// label "endproc"
+bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
+ StringRef Label;
+ if (getParser().parseIdentifier(Label))
+ return Error(Loc, "expected identifier for procedure");
+ if (getLexer().is(AsmToken::Identifier)) {
+ StringRef nextVal = getTok().getString();
+ SMLoc nextLoc = getTok().getLoc();
+ if (nextVal.equals_lower("far")) {
+ // TODO(epastor): Handle far procedure definitions.
+ Lex();
+ return Error(nextLoc, "far procedure definitions not yet supported");
+ } else if (nextVal.equals_lower("near")) {
+ Lex();
+ nextVal = getTok().getString();
+ nextLoc = getTok().getLoc();
+ }
+ }
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Label);
+
+ // Define symbol as simple function
+ getStreamer().BeginCOFFSymbolDef(Sym);
+ getStreamer().EmitCOFFSymbolStorageClass(2);
+ getStreamer().EmitCOFFSymbolType(0x20);
+ getStreamer().EndCOFFSymbolDef();
+
+ getStreamer().emitLabel(Sym, Loc);
+ CurrentProcedure = Label;
+ return false;
+}
+bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
+ StringRef Label;
+ SMLoc LabelLoc = getTok().getLoc();
+ if (getParser().parseIdentifier(Label))
+ return Error(LabelLoc, "expected identifier for procedure end");
+
+ if (CurrentProcedure.empty())
+ return Error(Loc, "endp outside of procedure block");
+ else if (CurrentProcedure != Label)
+ return Error(LabelLoc, "endp does not match current procedure '" +
+ CurrentProcedure + "'");
+ return false;
+}
+
+namespace llvm {
+
+MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
+
+} // end namespace llvm