mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[ms] [llvm-ml] Add a draft MASM parser
Summary: Many directives are unavailable, and support for others may be limited. This first draft has preliminary support for: - conditional directives (including errors), - data allocation (unsigned types up to 8 bytes, and ALIGN), - equates/variables (numeric and text), - and procedure directives (without parameters), as well as COMMENT, ECHO, INCLUDE, INCLUDELIB, PUBLIC, and EXTERN. Text variables (aka text macros) are expanded in-place wherever the identifier occurs. We deliberately ignore all ml.exe processor directives. Prominent features not yet supported: - structs - macros (both procedures and functions) - procedures (with specified parameters) - substitution & expansion operators Conditional directives are complicated by the fact that "ifdef rax" is a valid way to check if a file is being assembled for a 64-bit x86 processor; we add support for "ifdef <register>" in general, which requires adding a tryParseRegister method to all MCTargetAsmParsers. (Some targets require backtracking in the non-register case.) Reviewers: rnk, thakis Reviewed By: thakis Subscribers: kerbowa, merge_guards_bot, wuzish, arsenm, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, mgorny, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D72680
This commit is contained in:
parent
8b20125228
commit
ca668acee6
@ -156,6 +156,10 @@ protected:
|
||||
/// Defaults to false.
|
||||
bool AllowAtInName = false;
|
||||
|
||||
/// This is true if the assembler allows $ @ ? characters at the start of
|
||||
/// symbol names. Defaults to false.
|
||||
bool AllowSymbolAtNameStart = false;
|
||||
|
||||
/// If this is true, symbol names with invalid characters will be printed in
|
||||
/// quotes.
|
||||
bool SupportsQuotedNames = true;
|
||||
@ -537,6 +541,7 @@ public:
|
||||
const char *getCode64Directive() const { return Code64Directive; }
|
||||
unsigned getAssemblerDialect() const { return AssemblerDialect; }
|
||||
bool doesAllowAtInName() const { return AllowAtInName; }
|
||||
bool doesAllowSymbolAtNameStart() const { return AllowSymbolAtNameStart; }
|
||||
bool supportsNameQuoting() const { return SupportsQuotedNames; }
|
||||
|
||||
bool doesSupportDataRegionDirectives() const {
|
||||
|
@ -30,6 +30,7 @@ class AsmLexer : public MCAsmLexer {
|
||||
bool IsAtStartOfLine = true;
|
||||
bool IsAtStartOfStatement = true;
|
||||
bool IsPeeking = false;
|
||||
bool EndStatementAtEOF = true;
|
||||
|
||||
protected:
|
||||
/// LexToken - Read the next token and return its code.
|
||||
@ -41,7 +42,8 @@ public:
|
||||
AsmLexer &operator=(const AsmLexer &) = delete;
|
||||
~AsmLexer() override;
|
||||
|
||||
void setBuffer(StringRef Buf, const char *ptr = nullptr);
|
||||
void setBuffer(StringRef Buf, const char *ptr = nullptr,
|
||||
bool EndStatementAtEOF = true);
|
||||
|
||||
StringRef LexUntilEndOfStatement() override;
|
||||
|
||||
|
@ -250,6 +250,10 @@ public:
|
||||
/// characters and return the string contents.
|
||||
virtual bool parseEscapedString(std::string &Data) = 0;
|
||||
|
||||
/// Parse an angle-bracket delimited string at the current position if one is
|
||||
/// present, returning the string contents.
|
||||
virtual bool parseAngleBracketString(std::string &Data) = 0;
|
||||
|
||||
/// Skip to the end of the current statement, for error recovery.
|
||||
virtual void eatToEndOfStatement() = 0;
|
||||
|
||||
@ -300,10 +304,14 @@ public:
|
||||
SMLoc &EndLoc) = 0;
|
||||
};
|
||||
|
||||
/// Create an MCAsmParser instance.
|
||||
/// Create an MCAsmParser instance for parsing assembly similar to gas syntax
|
||||
MCAsmParser *createMCAsmParser(SourceMgr &, MCContext &, MCStreamer &,
|
||||
const MCAsmInfo &, unsigned CB = 0);
|
||||
|
||||
/// Create an MCAsmParser instance for parsing Microsoft MASM-style assembly
|
||||
MCAsmParser *createMCMasmParser(SourceMgr &, MCContext &, MCStreamer &,
|
||||
const MCAsmInfo &, unsigned CB = 0);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_MC_MCPARSER_MCASMPARSER_H
|
||||
|
@ -399,7 +399,7 @@ public:
|
||||
--I;
|
||||
MCSectionSubPair NewSection = I->first;
|
||||
|
||||
if (OldSection != NewSection)
|
||||
if (NewSection.first && OldSection != NewSection)
|
||||
ChangeSection(NewSection.first, NewSection.second);
|
||||
SectionStack.pop_back();
|
||||
return true;
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
int DwarfVersion = 0;
|
||||
|
||||
std::string ABIName;
|
||||
std::string AssemblyLanguage;
|
||||
std::string SplitDwarfFile;
|
||||
|
||||
/// Additional paths to search for `.include` directives when using the
|
||||
@ -68,6 +69,11 @@ public:
|
||||
/// textual name of the ABI that we want the backend to use, e.g. o32, or
|
||||
/// aapcs-linux.
|
||||
StringRef getABIName() const;
|
||||
|
||||
/// getAssemblyLanguage - If this returns a non-empty string this represents
|
||||
/// the textual name of the assembly language that we will use for this
|
||||
/// target, e.g. masm.
|
||||
StringRef getAssemblyLanguage() const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -36,7 +36,8 @@ AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) {
|
||||
|
||||
AsmLexer::~AsmLexer() = default;
|
||||
|
||||
void AsmLexer::setBuffer(StringRef Buf, const char *ptr) {
|
||||
void AsmLexer::setBuffer(StringRef Buf, const char *ptr,
|
||||
bool EndStatementAtEOF) {
|
||||
CurBuf = Buf;
|
||||
|
||||
if (ptr)
|
||||
@ -45,6 +46,7 @@ void AsmLexer::setBuffer(StringRef Buf, const char *ptr) {
|
||||
CurPtr = CurBuf.begin();
|
||||
|
||||
TokStart = nullptr;
|
||||
this->EndStatementAtEOF = EndStatementAtEOF;
|
||||
}
|
||||
|
||||
/// ReturnError - Set the error to the specified string at the specified
|
||||
@ -584,7 +586,7 @@ AsmToken AsmLexer::LexToken() {
|
||||
|
||||
// If we're missing a newline at EOF, make sure we still get an
|
||||
// EndOfStatement token before the Eof token.
|
||||
if (CurChar == EOF && !IsAtStartOfStatement) {
|
||||
if (CurChar == EOF && !IsAtStartOfStatement && EndStatementAtEOF) {
|
||||
IsAtStartOfLine = true;
|
||||
IsAtStartOfStatement = true;
|
||||
return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
|
||||
@ -594,15 +596,24 @@ AsmToken AsmLexer::LexToken() {
|
||||
IsAtStartOfStatement = false;
|
||||
switch (CurChar) {
|
||||
default:
|
||||
// Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
|
||||
if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
|
||||
return LexIdentifier();
|
||||
if (MAI.doesAllowSymbolAtNameStart()) {
|
||||
// Handle Microsoft-style identifier: [a-zA-Z_$.@?][a-zA-Z0-9_$.@?]*
|
||||
if (!isDigit(CurChar) &&
|
||||
IsIdentifierChar(CurChar, MAI.doesAllowAtInName()))
|
||||
return LexIdentifier();
|
||||
} else {
|
||||
// Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
|
||||
if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
|
||||
return LexIdentifier();
|
||||
}
|
||||
|
||||
// Unknown character, emit an error.
|
||||
return ReturnError(TokStart, "invalid character in input");
|
||||
case EOF:
|
||||
IsAtStartOfLine = true;
|
||||
IsAtStartOfStatement = true;
|
||||
if (EndStatementAtEOF) {
|
||||
IsAtStartOfLine = true;
|
||||
IsAtStartOfStatement = true;
|
||||
}
|
||||
return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
|
||||
case 0:
|
||||
case ' ':
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements the parser for assembly files.
|
||||
// This class implements a parser for assembly files similar to gas syntax.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -74,9 +74,7 @@ using namespace llvm;
|
||||
|
||||
MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default;
|
||||
|
||||
static cl::opt<unsigned> AsmMacroMaxNestingDepth(
|
||||
"asm-macro-max-nesting-depth", cl::init(20), cl::Hidden,
|
||||
cl::desc("The maximum nesting depth allowed for assembly macros."));
|
||||
extern cl::opt<unsigned> AsmMacroMaxNestingDepth;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -645,6 +643,7 @@ private:
|
||||
bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else"
|
||||
bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif
|
||||
bool parseEscapedString(std::string &Data) override;
|
||||
bool parseAngleBracketString(std::string &Data) override;
|
||||
|
||||
const MCExpr *applyModifierToExpr(const MCExpr *E,
|
||||
MCSymbolRefExpr::VariantKind Variant);
|
||||
@ -1365,7 +1364,7 @@ AsmParser::applyModifierToExpr(const MCExpr *E,
|
||||
/// implementation. GCC does not fully support this feature and so we will not
|
||||
/// support it.
|
||||
/// TODO: Adding single quote as a string.
|
||||
static bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) {
|
||||
static bool isAngleBracketString(SMLoc &StrLoc, SMLoc &EndLoc) {
|
||||
assert((StrLoc.getPointer() != nullptr) &&
|
||||
"Argument to the function cannot be a NULL value");
|
||||
const char *CharPtr = StrLoc.getPointer();
|
||||
@ -1383,7 +1382,7 @@ static bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) {
|
||||
}
|
||||
|
||||
/// creating a string without the escape characters '!'.
|
||||
static std::string altMacroString(StringRef AltMacroStr) {
|
||||
static std::string angleBracketString(StringRef AltMacroStr) {
|
||||
std::string Res;
|
||||
for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {
|
||||
if (AltMacroStr[Pos] == '!')
|
||||
@ -2497,7 +2496,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
|
||||
// is considered altMacroString!!!
|
||||
else if (AltMacroMode && Token.getString().front() == '<' &&
|
||||
Token.is(AsmToken::String)) {
|
||||
OS << altMacroString(Token.getStringContents());
|
||||
OS << angleBracketString(Token.getStringContents());
|
||||
}
|
||||
// We expect no quotes around the string's contents when
|
||||
// parsing for varargs.
|
||||
@ -2690,7 +2689,7 @@ bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
|
||||
StringRef(StrChar, EndChar - StrChar), Value);
|
||||
FA.Value.push_back(newToken);
|
||||
} else if (AltMacroMode && Lexer.is(AsmToken::Less) &&
|
||||
isAltmacroString(StrLoc, EndLoc)) {
|
||||
isAngleBracketString(StrLoc, EndLoc)) {
|
||||
const char *StrChar = StrLoc.getPointer();
|
||||
const char *EndChar = EndLoc.getPointer();
|
||||
jumpToLoc(EndLoc, CurBuffer);
|
||||
@ -2969,6 +2968,21 @@ bool AsmParser::parseEscapedString(std::string &Data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AsmParser::parseAngleBracketString(std::string &Data) {
|
||||
SMLoc EndLoc, StartLoc = getTok().getLoc();
|
||||
if (isAngleBracketString(StartLoc, EndLoc)) {
|
||||
const char *StartChar = StartLoc.getPointer() + 1;
|
||||
const char *EndChar = EndLoc.getPointer() - 1;
|
||||
jumpToLoc(EndLoc, CurBuffer);
|
||||
/// Eat from '<' to '>'
|
||||
Lex();
|
||||
|
||||
Data = angleBracketString(StringRef(StartChar, EndChar - StartChar));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// parseDirectiveAscii:
|
||||
/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
|
||||
bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
|
||||
|
@ -2,12 +2,14 @@ add_llvm_component_library(LLVMMCParser
|
||||
AsmLexer.cpp
|
||||
AsmParser.cpp
|
||||
COFFAsmParser.cpp
|
||||
COFFMasmParser.cpp
|
||||
DarwinAsmParser.cpp
|
||||
ELFAsmParser.cpp
|
||||
MCAsmLexer.cpp
|
||||
MCAsmParser.cpp
|
||||
MCAsmParserExtension.cpp
|
||||
MCTargetAsmParser.cpp
|
||||
MasmParser.cpp
|
||||
WasmAsmParser.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
|
386
lib/MC/MCParser/COFFMasmParser.cpp
Normal file
386
lib/MC/MCParser/COFFMasmParser.cpp
Normal file
@ -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
|
@ -13,6 +13,7 @@
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -20,6 +21,10 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
cl::opt<unsigned> AsmMacroMaxNestingDepth(
|
||||
"asm-macro-max-nesting-depth", cl::init(20), cl::Hidden,
|
||||
cl::desc("The maximum nesting depth allowed for assembly macros."));
|
||||
|
||||
MCAsmParser::MCAsmParser() {}
|
||||
|
||||
MCAsmParser::~MCAsmParser() = default;
|
||||
|
5566
lib/MC/MCParser/MasmParser.cpp
Normal file
5566
lib/MC/MCParser/MasmParser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,3 +21,7 @@ MCTargetOptions::MCTargetOptions()
|
||||
StringRef MCTargetOptions::getABIName() const {
|
||||
return ABIName;
|
||||
}
|
||||
|
||||
StringRef MCTargetOptions::getAssemblyLanguage() const {
|
||||
return AssemblyLanguage;
|
||||
}
|
||||
|
@ -145,6 +145,16 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
|
||||
UseIntegratedAssembler = true;
|
||||
}
|
||||
|
||||
void X86MCAsmInfoMicrosoftMASM::anchor() { }
|
||||
|
||||
X86MCAsmInfoMicrosoftMASM::X86MCAsmInfoMicrosoftMASM(const Triple &Triple)
|
||||
: X86MCAsmInfoMicrosoft(Triple) {
|
||||
DollarIsPC = true;
|
||||
SeparatorString = "\n";
|
||||
CommentString = ";";
|
||||
AllowSymbolAtNameStart = true;
|
||||
}
|
||||
|
||||
void X86MCAsmInfoGNUCOFF::anchor() { }
|
||||
|
||||
X86MCAsmInfoGNUCOFF::X86MCAsmInfoGNUCOFF(const Triple &Triple) {
|
||||
|
@ -49,6 +49,13 @@ public:
|
||||
explicit X86MCAsmInfoMicrosoft(const Triple &Triple);
|
||||
};
|
||||
|
||||
class X86MCAsmInfoMicrosoftMASM : public X86MCAsmInfoMicrosoft {
|
||||
void anchor() override;
|
||||
|
||||
public:
|
||||
explicit X86MCAsmInfoMicrosoftMASM(const Triple &Triple);
|
||||
};
|
||||
|
||||
class X86MCAsmInfoGNUCOFF : public MCAsmInfoGNUCOFF {
|
||||
void anchor() override;
|
||||
|
||||
|
@ -335,7 +335,10 @@ static MCAsmInfo *createX86MCAsmInfo(const MCRegisterInfo &MRI,
|
||||
MAI = new X86ELFMCAsmInfo(TheTriple);
|
||||
} else if (TheTriple.isWindowsMSVCEnvironment() ||
|
||||
TheTriple.isWindowsCoreCLREnvironment()) {
|
||||
MAI = new X86MCAsmInfoMicrosoft(TheTriple);
|
||||
if (Options.getAssemblyLanguage().equals_lower("masm"))
|
||||
MAI = new X86MCAsmInfoMicrosoftMASM(TheTriple);
|
||||
else
|
||||
MAI = new X86MCAsmInfoMicrosoft(TheTriple);
|
||||
} else if (TheTriple.isOSCygMing() ||
|
||||
TheTriple.isWindowsItaniumEnvironment()) {
|
||||
MAI = new X86MCAsmInfoGNUCOFF(TheTriple);
|
||||
|
@ -1,4 +1,3 @@
|
||||
# REQUIRES: x86-registered-target
|
||||
# RUN: not llvm-ml %t.blah -o /dev/null 2>&1 | FileCheck --check-prefix=ENOENT %s
|
||||
|
||||
# ENOENT: {{.*}}.blah: {{[Nn]}}o such file or directory
|
||||
|
3
test/tools/llvm-ml/lit.local.cfg
Normal file
3
test/tools/llvm-ml/lit.local.cfg
Normal file
@ -0,0 +1,3 @@
|
||||
if not ('X86' in config.root.targets):
|
||||
# We need support for X86.
|
||||
config.unsupported = True
|
@ -189,7 +189,8 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget,
|
||||
SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str,
|
||||
MCAsmInfo &MAI, MCSubtargetInfo &STI,
|
||||
MCInstrInfo &MCII, MCTargetOptions &MCOptions) {
|
||||
std::unique_ptr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI));
|
||||
std::unique_ptr<MCAsmParser> Parser(
|
||||
createMCMasmParser(SrcMgr, Ctx, Str, MAI));
|
||||
std::unique_ptr<MCTargetAsmParser> TAP(
|
||||
TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions));
|
||||
|
||||
@ -222,6 +223,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
|
||||
MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
|
||||
MCOptions.AssemblyLanguage = "masm";
|
||||
|
||||
const char *ProgName = argv[0];
|
||||
const Target *TheTarget = GetTarget(ProgName);
|
||||
|
@ -14,6 +14,7 @@ static_library("MCParser") {
|
||||
"MCAsmLexer.cpp",
|
||||
"MCAsmParser.cpp",
|
||||
"MCAsmParserExtension.cpp",
|
||||
"MasmParser.cpp",
|
||||
"MCTargetAsmParser.cpp",
|
||||
"WasmAsmParser.cpp",
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user