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 .StartsWith(".debug_", SectionKind::getMetadata()) 127 .Default(Optional<SectionKind>()); 128 if (!Kind.hasValue()) 129 return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); 130 131 MCSectionWasm *Section = getContext().getWasmSection(Name, Kind.getValue()); 132 133 // Update section flags if present in this .section directive 134 bool Passive = false; 135 if (parseSectionFlags(getTok().getStringContents(), Passive)) 136 return true; 137 138 if (Passive) { 139 if (!Section->isWasmData()) 140 return Parser->Error(getTok().getLoc(), 141 "Only data sections can be passive"); 142 Section->setPassive(); 143 } 144 145 Lex(); 146 147 if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") || 148 expect(AsmToken::EndOfStatement, "eol")) 149 return true; 150 151 auto WS = getContext().getWasmSection(Name, Kind.getValue()); 152 getStreamer().SwitchSection(WS); 153 return false; 154 } 155 156 // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize 157 // so maybe could be shared somehow. 158 bool parseDirectiveSize(StringRef, SMLoc) { 159 StringRef Name; 160 if (Parser->parseIdentifier(Name)) 161 return TokError("expected identifier in directive"); 162 auto Sym = getContext().getOrCreateSymbol(Name); 163 if (expect(AsmToken::Comma, ",")) 164 return true; 165 const MCExpr *Expr; 166 if (Parser->parseExpression(Expr)) 167 return true; 168 if (expect(AsmToken::EndOfStatement, "eol")) 169 return true; 170 // This is done automatically by the assembler for functions currently, 171 // so this is only currently needed for data sections: 172 getStreamer().emitELFSize(Sym, Expr); 173 return false; 174 } 175 176 bool parseDirectiveType(StringRef, SMLoc) { 177 // This could be the start of a function, check if followed by 178 // "label,@function" 179 if (!Lexer->is(AsmToken::Identifier)) 180 return error("Expected label after .type directive, got: ", 181 Lexer->getTok()); 182 auto WasmSym = cast<MCSymbolWasm>( 183 getStreamer().getContext().getOrCreateSymbol( 184 Lexer->getTok().getString())); 185 Lex(); 186 if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && 187 Lexer->is(AsmToken::Identifier))) 188 return error("Expected label,@type declaration, got: ", Lexer->getTok()); 189 auto TypeName = Lexer->getTok().getString(); 190 if (TypeName == "function") 191 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 192 else if (TypeName == "global") 193 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 194 else if (TypeName == "object") 195 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); 196 else 197 return error("Unknown WASM symbol type: ", Lexer->getTok()); 198 Lex(); 199 return expect(AsmToken::EndOfStatement, "EOL"); 200 } 201 202 // FIXME: Shared with ELF. 203 /// ParseDirectiveIdent 204 /// ::= .ident string 205 bool ParseDirectiveIdent(StringRef, SMLoc) { 206 if (getLexer().isNot(AsmToken::String)) 207 return TokError("unexpected token in '.ident' directive"); 208 StringRef Data = getTok().getIdentifier(); 209 Lex(); 210 if (getLexer().isNot(AsmToken::EndOfStatement)) 211 return TokError("unexpected token in '.ident' directive"); 212 Lex(); 213 getStreamer().emitIdent(Data); 214 return false; 215 } 216 217 // FIXME: Shared with ELF. 218 /// ParseDirectiveSymbolAttribute 219 /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] 220 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 221 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 222 .Case(".weak", MCSA_Weak) 223 .Case(".local", MCSA_Local) 224 .Case(".hidden", MCSA_Hidden) 225 .Case(".internal", MCSA_Internal) 226 .Case(".protected", MCSA_Protected) 227 .Default(MCSA_Invalid); 228 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 229 if (getLexer().isNot(AsmToken::EndOfStatement)) { 230 while (true) { 231 StringRef Name; 232 if (getParser().parseIdentifier(Name)) 233 return TokError("expected identifier in directive"); 234 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 235 getStreamer().emitSymbolAttribute(Sym, Attr); 236 if (getLexer().is(AsmToken::EndOfStatement)) 237 break; 238 if (getLexer().isNot(AsmToken::Comma)) 239 return TokError("unexpected token in directive"); 240 Lex(); 241 } 242 } 243 Lex(); 244 return false; 245 } 246 }; 247 248 } // end anonymous namespace 249 250 namespace llvm { 251 252 MCAsmParserExtension *createWasmAsmParser() { 253 return new WasmAsmParser; 254 } 255 256 } // end namespace llvm 257