1 //===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 // -- 8 // 9 // Note, this is for wasm, the binary format (analogous to ELF), not wasm, 10 // the instruction set (analogous to x86), for which parsing code lives in 11 // WebAssemblyAsmParser. 12 // 13 // This file contains processing for generic directives implemented using 14 // MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in 15 // WebAssemblyAsmParser. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "llvm/BinaryFormat/Wasm.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCParser/MCAsmLexer.h" 22 #include "llvm/MC/MCParser/MCAsmParser.h" 23 #include "llvm/MC/MCParser/MCAsmParserExtension.h" 24 #include "llvm/MC/MCSectionWasm.h" 25 #include "llvm/MC/MCStreamer.h" 26 #include "llvm/MC/MCSymbol.h" 27 #include "llvm/MC/MCSymbolWasm.h" 28 #include "llvm/Support/MachineValueType.h" 29 30 using namespace llvm; 31 32 namespace { 33 34 class WasmAsmParser : public MCAsmParserExtension { 35 MCAsmParser *Parser = nullptr; 36 MCAsmLexer *Lexer = nullptr; 37 38 template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)> 39 void addDirectiveHandler(StringRef Directive) { 40 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 41 this, HandleDirective<WasmAsmParser, HandlerMethod>); 42 43 getParser().addDirectiveHandler(Directive, Handler); 44 } 45 46 public: 47 WasmAsmParser() { BracketExpressionsSupported = true; } 48 49 void Initialize(MCAsmParser &P) override { 50 Parser = &P; 51 Lexer = &Parser->getLexer(); 52 // Call the base implementation. 53 this->MCAsmParserExtension::Initialize(*Parser); 54 55 addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text"); 56 addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section"); 57 addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size"); 58 addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type"); 59 addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident"); 60 addDirectiveHandler< 61 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak"); 62 addDirectiveHandler< 63 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".local"); 64 addDirectiveHandler< 65 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal"); 66 addDirectiveHandler< 67 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); 68 } 69 70 bool error(const StringRef &Msg, const AsmToken &Tok) { 71 return Parser->Error(Tok.getLoc(), Msg + Tok.getString()); 72 } 73 74 bool isNext(AsmToken::TokenKind Kind) { 75 auto Ok = Lexer->is(Kind); 76 if (Ok) 77 Lex(); 78 return Ok; 79 } 80 81 bool expect(AsmToken::TokenKind Kind, const char *KindName) { 82 if (!isNext(Kind)) 83 return error(std::string("Expected ") + KindName + ", instead got: ", 84 Lexer->getTok()); 85 return false; 86 } 87 88 bool parseSectionDirectiveText(StringRef, SMLoc) { 89 // FIXME: .text currently no-op. 90 return false; 91 } 92 93 bool parseSectionFlags(StringRef FlagStr, bool &Passive) { 94 SmallVector<StringRef, 2> Flags; 95 // If there are no flags, keep Flags empty 96 FlagStr.split(Flags, ",", -1, false); 97 for (auto &Flag : Flags) { 98 if (Flag == "passive") 99 Passive = true; 100 else 101 return error("Expected section flags, instead got: ", Lexer->getTok()); 102 } 103 return false; 104 } 105 106 bool parseSectionDirective(StringRef, SMLoc) { 107 StringRef Name; 108 if (Parser->parseIdentifier(Name)) 109 return TokError("expected identifier in directive"); 110 111 if (expect(AsmToken::Comma, ",")) 112 return true; 113 114 if (Lexer->isNot(AsmToken::String)) 115 return error("expected string in directive, instead got: ", Lexer->getTok()); 116 117 auto Kind = StringSwitch<Optional<SectionKind>>(Name) 118 .StartsWith(".data", SectionKind::getData()) 119 .StartsWith(".rodata", SectionKind::getReadOnly()) 120 .StartsWith(".text", SectionKind::getText()) 121 .StartsWith(".custom_section", SectionKind::getMetadata()) 122 .StartsWith(".bss", SectionKind::getBSS()) 123 // See use of .init_array in WasmObjectWriter and 124 // TargetLoweringObjectFileWasm 125 .StartsWith(".init_array", SectionKind::getData()) 126 .Default(Optional<SectionKind>()); 127 if (!Kind.hasValue()) 128 return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); 129 130 MCSectionWasm *Section = getContext().getWasmSection(Name, Kind.getValue()); 131 132 // Update section flags if present in this .section directive 133 bool Passive = false; 134 if (parseSectionFlags(getTok().getStringContents(), Passive)) 135 return true; 136 137 if (Passive) { 138 if (!Section->isWasmData()) 139 return Parser->Error(getTok().getLoc(), 140 "Only data sections can be passive"); 141 Section->setPassive(); 142 } 143 144 Lex(); 145 146 if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") || 147 expect(AsmToken::EndOfStatement, "eol")) 148 return true; 149 150 auto WS = getContext().getWasmSection(Name, Kind.getValue()); 151 getStreamer().SwitchSection(WS); 152 return false; 153 } 154 155 // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize 156 // so maybe could be shared somehow. 157 bool parseDirectiveSize(StringRef, SMLoc) { 158 StringRef Name; 159 if (Parser->parseIdentifier(Name)) 160 return TokError("expected identifier in directive"); 161 auto Sym = getContext().getOrCreateSymbol(Name); 162 if (expect(AsmToken::Comma, ",")) 163 return true; 164 const MCExpr *Expr; 165 if (Parser->parseExpression(Expr)) 166 return true; 167 if (expect(AsmToken::EndOfStatement, "eol")) 168 return true; 169 // This is done automatically by the assembler for functions currently, 170 // so this is only currently needed for data sections: 171 getStreamer().emitELFSize(Sym, Expr); 172 return false; 173 } 174 175 bool parseDirectiveType(StringRef, SMLoc) { 176 // This could be the start of a function, check if followed by 177 // "label,@function" 178 if (!Lexer->is(AsmToken::Identifier)) 179 return error("Expected label after .type directive, got: ", 180 Lexer->getTok()); 181 auto WasmSym = cast<MCSymbolWasm>( 182 getStreamer().getContext().getOrCreateSymbol( 183 Lexer->getTok().getString())); 184 Lex(); 185 if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && 186 Lexer->is(AsmToken::Identifier))) 187 return error("Expected label,@type declaration, got: ", Lexer->getTok()); 188 auto TypeName = Lexer->getTok().getString(); 189 if (TypeName == "function") 190 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 191 else if (TypeName == "global") 192 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 193 else if (TypeName == "object") 194 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); 195 else 196 return error("Unknown WASM symbol type: ", Lexer->getTok()); 197 Lex(); 198 return expect(AsmToken::EndOfStatement, "EOL"); 199 } 200 201 // FIXME: Shared with ELF. 202 /// ParseDirectiveIdent 203 /// ::= .ident string 204 bool ParseDirectiveIdent(StringRef, SMLoc) { 205 if (getLexer().isNot(AsmToken::String)) 206 return TokError("unexpected token in '.ident' directive"); 207 StringRef Data = getTok().getIdentifier(); 208 Lex(); 209 if (getLexer().isNot(AsmToken::EndOfStatement)) 210 return TokError("unexpected token in '.ident' directive"); 211 Lex(); 212 getStreamer().EmitIdent(Data); 213 return false; 214 } 215 216 // FIXME: Shared with ELF. 217 /// ParseDirectiveSymbolAttribute 218 /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] 219 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 220 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 221 .Case(".weak", MCSA_Weak) 222 .Case(".local", MCSA_Local) 223 .Case(".hidden", MCSA_Hidden) 224 .Case(".internal", MCSA_Internal) 225 .Case(".protected", MCSA_Protected) 226 .Default(MCSA_Invalid); 227 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 228 if (getLexer().isNot(AsmToken::EndOfStatement)) { 229 while (true) { 230 StringRef Name; 231 if (getParser().parseIdentifier(Name)) 232 return TokError("expected identifier in directive"); 233 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 234 getStreamer().EmitSymbolAttribute(Sym, Attr); 235 if (getLexer().is(AsmToken::EndOfStatement)) 236 break; 237 if (getLexer().isNot(AsmToken::Comma)) 238 return TokError("unexpected token in directive"); 239 Lex(); 240 } 241 } 242 Lex(); 243 return false; 244 } 245 }; 246 247 } // end anonymous namespace 248 249 namespace llvm { 250 251 MCAsmParserExtension *createWasmAsmParser() { 252 return new WasmAsmParser; 253 } 254 255 } // end namespace llvm 256