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, bool &Group) { 94 for (char C : FlagStr) { 95 switch (C) { 96 case 'p': 97 Passive = true; 98 break; 99 case 'G': 100 Group = true; 101 break; 102 default: 103 return Parser->Error(getTok().getLoc(), 104 StringRef("Unexepcted section flag: ") + FlagStr); 105 } 106 } 107 return false; 108 } 109 110 bool parseGroup(StringRef &GroupName) { 111 if (Lexer->isNot(AsmToken::Comma)) 112 return TokError("expected group name"); 113 Lex(); 114 if (Lexer->is(AsmToken::Integer)) { 115 GroupName = getTok().getString(); 116 Lex(); 117 } else if (Parser->parseIdentifier(GroupName)) { 118 return TokError("invalid group name"); 119 } 120 if (Lexer->is(AsmToken::Comma)) { 121 Lex(); 122 StringRef Linkage; 123 if (Parser->parseIdentifier(Linkage)) 124 return TokError("invalid linkage"); 125 if (Linkage != "comdat") 126 return TokError("Linkage must be 'comdat'"); 127 } 128 return false; 129 } 130 131 bool parseSectionDirective(StringRef, SMLoc) { 132 StringRef Name; 133 if (Parser->parseIdentifier(Name)) 134 return TokError("expected identifier in directive"); 135 136 if (expect(AsmToken::Comma, ",")) 137 return true; 138 139 if (Lexer->isNot(AsmToken::String)) 140 return error("expected string in directive, instead got: ", Lexer->getTok()); 141 142 auto Kind = StringSwitch<Optional<SectionKind>>(Name) 143 .StartsWith(".data", SectionKind::getData()) 144 .StartsWith(".tdata", SectionKind::getThreadData()) 145 .StartsWith(".tbss", SectionKind::getThreadBSS()) 146 .StartsWith(".rodata", SectionKind::getReadOnly()) 147 .StartsWith(".text", SectionKind::getText()) 148 .StartsWith(".custom_section", SectionKind::getMetadata()) 149 .StartsWith(".bss", SectionKind::getBSS()) 150 // See use of .init_array in WasmObjectWriter and 151 // TargetLoweringObjectFileWasm 152 .StartsWith(".init_array", SectionKind::getData()) 153 .StartsWith(".debug_", SectionKind::getMetadata()) 154 .Default(Optional<SectionKind>()); 155 if (!Kind.hasValue()) 156 return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name); 157 158 159 // Update section flags if present in this .section directive 160 bool Passive = false; 161 bool Group = false; 162 if (parseSectionFlags(getTok().getStringContents(), Passive, Group)) 163 return true; 164 165 Lex(); 166 167 if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@")) 168 return true; 169 170 StringRef GroupName; 171 if (Group && parseGroup(GroupName)) 172 return true; 173 174 if (expect(AsmToken::EndOfStatement, "eol")) 175 return true; 176 177 // TODO: Parse UniqueID 178 MCSectionWasm *WS = getContext().getWasmSection( 179 Name, Kind.getValue(), GroupName, MCContext::GenericSectionID); 180 if (Passive) { 181 if (!WS->isWasmData()) 182 return Parser->Error(getTok().getLoc(), 183 "Only data sections can be passive"); 184 WS->setPassive(); 185 } 186 getStreamer().SwitchSection(WS); 187 return false; 188 } 189 190 // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize 191 // so maybe could be shared somehow. 192 bool parseDirectiveSize(StringRef, SMLoc) { 193 StringRef Name; 194 if (Parser->parseIdentifier(Name)) 195 return TokError("expected identifier in directive"); 196 auto Sym = getContext().getOrCreateSymbol(Name); 197 if (expect(AsmToken::Comma, ",")) 198 return true; 199 const MCExpr *Expr; 200 if (Parser->parseExpression(Expr)) 201 return true; 202 if (expect(AsmToken::EndOfStatement, "eol")) 203 return true; 204 // This is done automatically by the assembler for functions currently, 205 // so this is only currently needed for data sections: 206 getStreamer().emitELFSize(Sym, Expr); 207 return false; 208 } 209 210 bool parseDirectiveType(StringRef, SMLoc) { 211 // This could be the start of a function, check if followed by 212 // "label,@function" 213 if (!Lexer->is(AsmToken::Identifier)) 214 return error("Expected label after .type directive, got: ", 215 Lexer->getTok()); 216 auto WasmSym = cast<MCSymbolWasm>( 217 getStreamer().getContext().getOrCreateSymbol( 218 Lexer->getTok().getString())); 219 Lex(); 220 if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && 221 Lexer->is(AsmToken::Identifier))) 222 return error("Expected label,@type declaration, got: ", Lexer->getTok()); 223 auto TypeName = Lexer->getTok().getString(); 224 if (TypeName == "function") { 225 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 226 auto *Current = 227 cast<MCSectionWasm>(getStreamer().getCurrentSection().first); 228 if (Current->getGroup()) 229 WasmSym->setComdat(true); 230 } else if (TypeName == "global") 231 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 232 else if (TypeName == "object") 233 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); 234 else 235 return error("Unknown WASM symbol type: ", Lexer->getTok()); 236 Lex(); 237 return expect(AsmToken::EndOfStatement, "EOL"); 238 } 239 240 // FIXME: Shared with ELF. 241 /// ParseDirectiveIdent 242 /// ::= .ident string 243 bool ParseDirectiveIdent(StringRef, SMLoc) { 244 if (getLexer().isNot(AsmToken::String)) 245 return TokError("unexpected token in '.ident' directive"); 246 StringRef Data = getTok().getIdentifier(); 247 Lex(); 248 if (getLexer().isNot(AsmToken::EndOfStatement)) 249 return TokError("unexpected token in '.ident' directive"); 250 Lex(); 251 getStreamer().emitIdent(Data); 252 return false; 253 } 254 255 // FIXME: Shared with ELF. 256 /// ParseDirectiveSymbolAttribute 257 /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] 258 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 259 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 260 .Case(".weak", MCSA_Weak) 261 .Case(".local", MCSA_Local) 262 .Case(".hidden", MCSA_Hidden) 263 .Case(".internal", MCSA_Internal) 264 .Case(".protected", MCSA_Protected) 265 .Default(MCSA_Invalid); 266 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 267 if (getLexer().isNot(AsmToken::EndOfStatement)) { 268 while (true) { 269 StringRef Name; 270 if (getParser().parseIdentifier(Name)) 271 return TokError("expected identifier in directive"); 272 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 273 getStreamer().emitSymbolAttribute(Sym, Attr); 274 if (getLexer().is(AsmToken::EndOfStatement)) 275 break; 276 if (getLexer().isNot(AsmToken::Comma)) 277 return TokError("unexpected token in directive"); 278 Lex(); 279 } 280 } 281 Lex(); 282 return false; 283 } 284 }; 285 286 } // end anonymous namespace 287 288 namespace llvm { 289 290 MCAsmParserExtension *createWasmAsmParser() { 291 return new WasmAsmParser; 292 } 293 294 } // end namespace llvm 295