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