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