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