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