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/MCSymbolWasm.h" 27 #include "llvm/Support/Casting.h" 28 29 using namespace llvm; 30 31 namespace { 32 33 class WasmAsmParser : public MCAsmParserExtension { 34 MCAsmParser *Parser = nullptr; 35 MCAsmLexer *Lexer = nullptr; 36 37 template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)> 38 void addDirectiveHandler(StringRef Directive) { 39 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( 40 this, HandleDirective<WasmAsmParser, HandlerMethod>); 41 42 getParser().addDirectiveHandler(Directive, Handler); 43 } 44 45 public: 46 WasmAsmParser() { BracketExpressionsSupported = true; } 47 48 void Initialize(MCAsmParser &P) override { 49 Parser = &P; 50 Lexer = &Parser->getLexer(); 51 // Call the base implementation. 52 this->MCAsmParserExtension::Initialize(*Parser); 53 54 addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text"); 55 addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section"); 56 addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size"); 57 addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type"); 58 addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident"); 59 addDirectiveHandler< 60 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak"); 61 addDirectiveHandler< 62 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".local"); 63 addDirectiveHandler< 64 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal"); 65 addDirectiveHandler< 66 &WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); 67 } 68 69 bool error(const StringRef &Msg, const AsmToken &Tok) { 70 return Parser->Error(Tok.getLoc(), Msg + Tok.getString()); 71 } 72 73 bool isNext(AsmToken::TokenKind Kind) { 74 auto Ok = Lexer->is(Kind); 75 if (Ok) 76 Lex(); 77 return Ok; 78 } 79 80 bool expect(AsmToken::TokenKind Kind, const char *KindName) { 81 if (!isNext(Kind)) 82 return error(std::string("Expected ") + KindName + ", instead got: ", 83 Lexer->getTok()); 84 return false; 85 } 86 87 bool parseSectionDirectiveText(StringRef, SMLoc) { 88 // FIXME: .text currently no-op. 89 return false; 90 } 91 92 uint32_t parseSectionFlags(StringRef FlagStr, bool &Passive, bool &Group) { 93 uint32_t flags = 0; 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 case 'T': 103 flags |= wasm::WASM_SEG_FLAG_TLS; 104 break; 105 case 'S': 106 flags |= wasm::WASM_SEG_FLAG_STRINGS; 107 break; 108 default: 109 return -1U; 110 } 111 } 112 return flags; 113 } 114 115 bool parseGroup(StringRef &GroupName) { 116 if (Lexer->isNot(AsmToken::Comma)) 117 return TokError("expected group name"); 118 Lex(); 119 if (Lexer->is(AsmToken::Integer)) { 120 GroupName = getTok().getString(); 121 Lex(); 122 } else if (Parser->parseIdentifier(GroupName)) { 123 return TokError("invalid group name"); 124 } 125 if (Lexer->is(AsmToken::Comma)) { 126 Lex(); 127 StringRef Linkage; 128 if (Parser->parseIdentifier(Linkage)) 129 return TokError("invalid linkage"); 130 if (Linkage != "comdat") 131 return TokError("Linkage must be 'comdat'"); 132 } 133 return false; 134 } 135 136 bool parseSectionDirective(StringRef, SMLoc loc) { 137 StringRef Name; 138 if (Parser->parseIdentifier(Name)) 139 return TokError("expected identifier in directive"); 140 141 if (expect(AsmToken::Comma, ",")) 142 return true; 143 144 if (Lexer->isNot(AsmToken::String)) 145 return error("expected string in directive, instead got: ", Lexer->getTok()); 146 147 auto Kind = StringSwitch<Optional<SectionKind>>(Name) 148 .StartsWith(".data", SectionKind::getData()) 149 .StartsWith(".tdata", SectionKind::getThreadData()) 150 .StartsWith(".tbss", SectionKind::getThreadBSS()) 151 .StartsWith(".rodata", SectionKind::getReadOnly()) 152 .StartsWith(".text", SectionKind::getText()) 153 .StartsWith(".custom_section", SectionKind::getMetadata()) 154 .StartsWith(".bss", SectionKind::getBSS()) 155 // See use of .init_array in WasmObjectWriter and 156 // TargetLoweringObjectFileWasm 157 .StartsWith(".init_array", SectionKind::getData()) 158 .StartsWith(".debug_", SectionKind::getMetadata()) 159 .Default(SectionKind::getData()); 160 161 // Update section flags if present in this .section directive 162 bool Passive = false; 163 bool Group = false; 164 uint32_t Flags = 165 parseSectionFlags(getTok().getStringContents(), Passive, Group); 166 if (Flags == -1U) 167 return TokError("unknown flag"); 168 169 Lex(); 170 171 if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@")) 172 return true; 173 174 StringRef GroupName; 175 if (Group && parseGroup(GroupName)) 176 return true; 177 178 if (expect(AsmToken::EndOfStatement, "eol")) 179 return true; 180 181 // TODO: Parse UniqueID 182 MCSectionWasm *WS = getContext().getWasmSection( 183 Name, Kind.getValue(), Flags, GroupName, MCContext::GenericSectionID); 184 185 if (WS->getSegmentFlags() != Flags) 186 Parser->Error(loc, "changed section flags for " + Name + 187 ", expected: 0x" + 188 utohexstr(WS->getSegmentFlags())); 189 190 if (Passive) { 191 if (!WS->isWasmData()) 192 return Parser->Error(loc, "Only data sections can be passive"); 193 WS->setPassive(); 194 } 195 196 getStreamer().SwitchSection(WS); 197 return false; 198 } 199 200 // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize 201 // so maybe could be shared somehow. 202 bool parseDirectiveSize(StringRef, SMLoc) { 203 StringRef Name; 204 if (Parser->parseIdentifier(Name)) 205 return TokError("expected identifier in directive"); 206 auto Sym = getContext().getOrCreateSymbol(Name); 207 if (expect(AsmToken::Comma, ",")) 208 return true; 209 const MCExpr *Expr; 210 if (Parser->parseExpression(Expr)) 211 return true; 212 if (expect(AsmToken::EndOfStatement, "eol")) 213 return true; 214 // This is done automatically by the assembler for functions currently, 215 // so this is only currently needed for data sections: 216 getStreamer().emitELFSize(Sym, Expr); 217 return false; 218 } 219 220 bool parseDirectiveType(StringRef, SMLoc) { 221 // This could be the start of a function, check if followed by 222 // "label,@function" 223 if (!Lexer->is(AsmToken::Identifier)) 224 return error("Expected label after .type directive, got: ", 225 Lexer->getTok()); 226 auto WasmSym = cast<MCSymbolWasm>( 227 getStreamer().getContext().getOrCreateSymbol( 228 Lexer->getTok().getString())); 229 Lex(); 230 if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) && 231 Lexer->is(AsmToken::Identifier))) 232 return error("Expected label,@type declaration, got: ", Lexer->getTok()); 233 auto TypeName = Lexer->getTok().getString(); 234 if (TypeName == "function") { 235 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 236 auto *Current = 237 cast<MCSectionWasm>(getStreamer().getCurrentSection().first); 238 if (Current->getGroup()) 239 WasmSym->setComdat(true); 240 } else if (TypeName == "global") 241 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); 242 else if (TypeName == "object") 243 WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA); 244 else 245 return error("Unknown WASM symbol type: ", Lexer->getTok()); 246 Lex(); 247 return expect(AsmToken::EndOfStatement, "EOL"); 248 } 249 250 // FIXME: Shared with ELF. 251 /// ParseDirectiveIdent 252 /// ::= .ident string 253 bool ParseDirectiveIdent(StringRef, SMLoc) { 254 if (getLexer().isNot(AsmToken::String)) 255 return TokError("unexpected token in '.ident' directive"); 256 StringRef Data = getTok().getIdentifier(); 257 Lex(); 258 if (getLexer().isNot(AsmToken::EndOfStatement)) 259 return TokError("unexpected token in '.ident' directive"); 260 Lex(); 261 getStreamer().emitIdent(Data); 262 return false; 263 } 264 265 // FIXME: Shared with ELF. 266 /// ParseDirectiveSymbolAttribute 267 /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] 268 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { 269 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) 270 .Case(".weak", MCSA_Weak) 271 .Case(".local", MCSA_Local) 272 .Case(".hidden", MCSA_Hidden) 273 .Case(".internal", MCSA_Internal) 274 .Case(".protected", MCSA_Protected) 275 .Default(MCSA_Invalid); 276 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); 277 if (getLexer().isNot(AsmToken::EndOfStatement)) { 278 while (true) { 279 StringRef Name; 280 if (getParser().parseIdentifier(Name)) 281 return TokError("expected identifier in directive"); 282 MCSymbol *Sym = getContext().getOrCreateSymbol(Name); 283 getStreamer().emitSymbolAttribute(Sym, Attr); 284 if (getLexer().is(AsmToken::EndOfStatement)) 285 break; 286 if (getLexer().isNot(AsmToken::Comma)) 287 return TokError("unexpected token in directive"); 288 Lex(); 289 } 290 } 291 Lex(); 292 return false; 293 } 294 }; 295 296 } // end anonymous namespace 297 298 namespace llvm { 299 300 MCAsmParserExtension *createWasmAsmParser() { 301 return new WasmAsmParser; 302 } 303 304 } // end namespace llvm 305