123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415 |
- //===- 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/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/MCSymbolCOFF.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 ParseDirectiveAlias(StringRef, SMLoc);
- bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
- bool ParseSEHDirectiveEndProlog(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
- addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
- ".allocstack");
- addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
- ".endprolog");
- // Code label directives
- // label
- // org
- // Conditional control flow directives
- // .break
- // .continue
- // .else
- // .elseif
- // .endif
- // .endw
- // .if
- // .repeat
- // .until
- // .untilcxz
- // .while
- // Data allocation directives
- // align
- // even
- // mmword
- // tbyte
- // xmmword
- // ymmword
- // 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
- // goto
- // Miscellaneous directives
- addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
- // assume
- // .fpo
- addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
- "includelib");
- // option
- // popcontext
- // pushcontext
- // .safeseh
- // Procedure directives
- addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
- // invoke (32-bit only)
- addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
- // proto
- // Processor directives; all ignored
- 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");
- // 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
- // record
- // typedef
- }
- 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;
- bool CurrentProcedureFramed;
- 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_insensitive("far")) {
- // TODO(epastor): Handle far procedure definitions.
- Lex();
- return Error(nextLoc, "far procedure definitions not yet supported");
- } else if (nextVal.equals_insensitive("near")) {
- Lex();
- nextVal = getTok().getString();
- nextLoc = getTok().getLoc();
- }
- }
- MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
- // Define symbol as simple external function
- Sym->setExternal(true);
- Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
- bool Framed = false;
- if (getLexer().is(AsmToken::Identifier) &&
- getTok().getString().equals_insensitive("frame")) {
- Lex();
- Framed = true;
- getStreamer().EmitWinCFIStartProc(Sym, Loc);
- }
- getStreamer().emitLabel(Sym, Loc);
- CurrentProcedure = Label;
- CurrentProcedureFramed = Framed;
- 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 + "'");
- if (CurrentProcedureFramed) {
- getStreamer().EmitWinCFIEndProc(Loc);
- }
- CurrentProcedure = "";
- CurrentProcedureFramed = false;
- return false;
- }
- bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
- std::string AliasName, ActualName;
- if (getTok().isNot(AsmToken::Less) ||
- getParser().parseAngleBracketString(AliasName))
- return Error(getTok().getLoc(), "expected <aliasName>");
- if (getParser().parseToken(AsmToken::Equal))
- return addErrorSuffix(" in " + Directive + " directive");
- if (getTok().isNot(AsmToken::Less) ||
- getParser().parseAngleBracketString(ActualName))
- return Error(getTok().getLoc(), "expected <actualName>");
- MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
- MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
- getStreamer().emitWeakReference(Alias, Actual);
- return false;
- }
- bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
- SMLoc Loc) {
- int64_t Size;
- SMLoc SizeLoc = getTok().getLoc();
- if (getParser().parseAbsoluteExpression(Size))
- return Error(SizeLoc, "expected integer size");
- if (Size % 8 != 0)
- return Error(SizeLoc, "stack size must be a multiple of 8");
- getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
- return false;
- }
- bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
- SMLoc Loc) {
- getStreamer().EmitWinCFIEndProlog(Loc);
- return false;
- }
- namespace llvm {
- MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
- } // end namespace llvm
|