Path: blob/main/contrib/llvm-project/llvm/lib/MC/MCParser/WasmAsmParser.cpp
35269 views
//===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6// --7//8// Note, this is for wasm, the binary format (analogous to ELF), not wasm,9// the instruction set (analogous to x86), for which parsing code lives in10// WebAssemblyAsmParser.11//12// This file contains processing for generic directives implemented using13// MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in14// WebAssemblyAsmParser.15//16//===----------------------------------------------------------------------===//1718#include "llvm/ADT/StringExtras.h"19#include "llvm/BinaryFormat/Wasm.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCObjectFileInfo.h"22#include "llvm/MC/MCParser/MCAsmLexer.h"23#include "llvm/MC/MCParser/MCAsmParser.h"24#include "llvm/MC/MCParser/MCAsmParserExtension.h"25#include "llvm/MC/MCSectionWasm.h"26#include "llvm/MC/MCStreamer.h"27#include "llvm/MC/MCSymbolWasm.h"28#include "llvm/Support/Casting.h"29#include <optional>3031using namespace llvm;3233namespace {3435class WasmAsmParser : public MCAsmParserExtension {36MCAsmParser *Parser = nullptr;37MCAsmLexer *Lexer = nullptr;3839template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)>40void addDirectiveHandler(StringRef Directive) {41MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(42this, HandleDirective<WasmAsmParser, HandlerMethod>);4344getParser().addDirectiveHandler(Directive, Handler);45}4647public:48WasmAsmParser() { BracketExpressionsSupported = true; }4950void Initialize(MCAsmParser &P) override {51Parser = &P;52Lexer = &Parser->getLexer();53// Call the base implementation.54this->MCAsmParserExtension::Initialize(*Parser);5556addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text");57addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveData>(".data");58addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section");59addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size");60addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type");61addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident");62addDirectiveHandler<63&WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak");64addDirectiveHandler<65&WasmAsmParser::ParseDirectiveSymbolAttribute>(".local");66addDirectiveHandler<67&WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal");68addDirectiveHandler<69&WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden");70}7172bool error(const StringRef &Msg, const AsmToken &Tok) {73return Parser->Error(Tok.getLoc(), Msg + Tok.getString());74}7576bool isNext(AsmToken::TokenKind Kind) {77auto Ok = Lexer->is(Kind);78if (Ok)79Lex();80return Ok;81}8283bool expect(AsmToken::TokenKind Kind, const char *KindName) {84if (!isNext(Kind))85return error(std::string("Expected ") + KindName + ", instead got: ",86Lexer->getTok());87return false;88}8990bool parseSectionDirectiveText(StringRef, SMLoc) {91// FIXME: .text currently no-op.92return false;93}9495bool parseSectionDirectiveData(StringRef, SMLoc) {96auto *S = getContext().getObjectFileInfo()->getDataSection();97getStreamer().switchSection(S);98return false;99}100101uint32_t parseSectionFlags(StringRef FlagStr, bool &Passive, bool &Group) {102uint32_t flags = 0;103for (char C : FlagStr) {104switch (C) {105case 'p':106Passive = true;107break;108case 'G':109Group = true;110break;111case 'T':112flags |= wasm::WASM_SEG_FLAG_TLS;113break;114case 'S':115flags |= wasm::WASM_SEG_FLAG_STRINGS;116break;117case 'R':118flags |= wasm::WASM_SEG_FLAG_RETAIN;119break;120default:121return -1U;122}123}124return flags;125}126127bool parseGroup(StringRef &GroupName) {128if (Lexer->isNot(AsmToken::Comma))129return TokError("expected group name");130Lex();131if (Lexer->is(AsmToken::Integer)) {132GroupName = getTok().getString();133Lex();134} else if (Parser->parseIdentifier(GroupName)) {135return TokError("invalid group name");136}137if (Lexer->is(AsmToken::Comma)) {138Lex();139StringRef Linkage;140if (Parser->parseIdentifier(Linkage))141return TokError("invalid linkage");142if (Linkage != "comdat")143return TokError("Linkage must be 'comdat'");144}145return false;146}147148bool parseSectionDirective(StringRef, SMLoc loc) {149StringRef Name;150if (Parser->parseIdentifier(Name))151return TokError("expected identifier in directive");152153if (expect(AsmToken::Comma, ","))154return true;155156if (Lexer->isNot(AsmToken::String))157return error("expected string in directive, instead got: ", Lexer->getTok());158159auto Kind = StringSwitch<std::optional<SectionKind>>(Name)160.StartsWith(".data", SectionKind::getData())161.StartsWith(".tdata", SectionKind::getThreadData())162.StartsWith(".tbss", SectionKind::getThreadBSS())163.StartsWith(".rodata", SectionKind::getReadOnly())164.StartsWith(".text", SectionKind::getText())165.StartsWith(".custom_section", SectionKind::getMetadata())166.StartsWith(".bss", SectionKind::getBSS())167// See use of .init_array in WasmObjectWriter and168// TargetLoweringObjectFileWasm169.StartsWith(".init_array", SectionKind::getData())170.StartsWith(".debug_", SectionKind::getMetadata())171.Default(SectionKind::getData());172173// Update section flags if present in this .section directive174bool Passive = false;175bool Group = false;176uint32_t Flags =177parseSectionFlags(getTok().getStringContents(), Passive, Group);178if (Flags == -1U)179return TokError("unknown flag");180181Lex();182183if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@"))184return true;185186StringRef GroupName;187if (Group && parseGroup(GroupName))188return true;189190if (expect(AsmToken::EndOfStatement, "eol"))191return true;192193// TODO: Parse UniqueID194MCSectionWasm *WS = getContext().getWasmSection(195Name, *Kind, Flags, GroupName, MCContext::GenericSectionID);196197if (WS->getSegmentFlags() != Flags)198Parser->Error(loc, "changed section flags for " + Name +199", expected: 0x" +200utohexstr(WS->getSegmentFlags()));201202if (Passive) {203if (!WS->isWasmData())204return Parser->Error(loc, "Only data sections can be passive");205WS->setPassive();206}207208getStreamer().switchSection(WS);209return false;210}211212// TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize213// so maybe could be shared somehow.214bool parseDirectiveSize(StringRef, SMLoc Loc) {215StringRef Name;216if (Parser->parseIdentifier(Name))217return TokError("expected identifier in directive");218auto Sym = getContext().getOrCreateSymbol(Name);219if (expect(AsmToken::Comma, ","))220return true;221const MCExpr *Expr;222if (Parser->parseExpression(Expr))223return true;224if (expect(AsmToken::EndOfStatement, "eol"))225return true;226auto WasmSym = cast<MCSymbolWasm>(Sym);227if (WasmSym->isFunction()) {228// Ignore .size directives for function symbols. They get their size229// set automatically based on their content.230Warning(Loc, ".size directive ignored for function symbols");231} else {232getStreamer().emitELFSize(Sym, Expr);233}234return false;235}236237bool parseDirectiveType(StringRef, SMLoc) {238// This could be the start of a function, check if followed by239// "label,@function"240if (!Lexer->is(AsmToken::Identifier))241return error("Expected label after .type directive, got: ",242Lexer->getTok());243auto WasmSym = cast<MCSymbolWasm>(244getStreamer().getContext().getOrCreateSymbol(245Lexer->getTok().getString()));246Lex();247if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) &&248Lexer->is(AsmToken::Identifier)))249return error("Expected label,@type declaration, got: ", Lexer->getTok());250auto TypeName = Lexer->getTok().getString();251if (TypeName == "function") {252WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);253auto *Current =254cast<MCSectionWasm>(getStreamer().getCurrentSectionOnly());255if (Current->getGroup())256WasmSym->setComdat(true);257} else if (TypeName == "global")258WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);259else if (TypeName == "object")260WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);261else262return error("Unknown WASM symbol type: ", Lexer->getTok());263Lex();264return expect(AsmToken::EndOfStatement, "EOL");265}266267// FIXME: Shared with ELF.268/// ParseDirectiveIdent269/// ::= .ident string270bool ParseDirectiveIdent(StringRef, SMLoc) {271if (getLexer().isNot(AsmToken::String))272return TokError("unexpected token in '.ident' directive");273StringRef Data = getTok().getIdentifier();274Lex();275if (getLexer().isNot(AsmToken::EndOfStatement))276return TokError("unexpected token in '.ident' directive");277Lex();278getStreamer().emitIdent(Data);279return false;280}281282// FIXME: Shared with ELF.283/// ParseDirectiveSymbolAttribute284/// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ]285bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {286MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)287.Case(".weak", MCSA_Weak)288.Case(".local", MCSA_Local)289.Case(".hidden", MCSA_Hidden)290.Case(".internal", MCSA_Internal)291.Case(".protected", MCSA_Protected)292.Default(MCSA_Invalid);293assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");294if (getLexer().isNot(AsmToken::EndOfStatement)) {295while (true) {296StringRef Name;297if (getParser().parseIdentifier(Name))298return TokError("expected identifier in directive");299MCSymbol *Sym = getContext().getOrCreateSymbol(Name);300getStreamer().emitSymbolAttribute(Sym, Attr);301if (getLexer().is(AsmToken::EndOfStatement))302break;303if (getLexer().isNot(AsmToken::Comma))304return TokError("unexpected token in directive");305Lex();306}307}308Lex();309return false;310}311};312313} // end anonymous namespace314315namespace llvm {316317MCAsmParserExtension *createWasmAsmParser() {318return new WasmAsmParser;319}320321} // end namespace llvm322323324