1 //===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===//
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
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.
13 // This file contains processing for generic directives implemented using
14 // MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in
15 // WebAssemblyAsmParser.
17 //===----------------------------------------------------------------------===//
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"
36 class WasmAsmParser
: public MCAsmParserExtension
{
37 MCAsmParser
*Parser
= nullptr;
38 MCAsmLexer
*Lexer
= nullptr;
40 template<bool (WasmAsmParser::*HandlerMethod
)(StringRef
, SMLoc
)>
41 void addDirectiveHandler(StringRef Directive
) {
42 MCAsmParser::ExtensionDirectiveHandler Handler
= std::make_pair(
43 this, HandleDirective
<WasmAsmParser
, HandlerMethod
>);
45 getParser().addDirectiveHandler(Directive
, Handler
);
49 WasmAsmParser() { BracketExpressionsSupported
= true; }
51 void Initialize(MCAsmParser
&P
) override
{
53 Lexer
= &Parser
->getLexer();
54 // Call the base implementation.
55 this->MCAsmParserExtension::Initialize(*Parser
);
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");
64 &WasmAsmParser::ParseDirectiveSymbolAttribute
>(".weak");
66 &WasmAsmParser::ParseDirectiveSymbolAttribute
>(".local");
68 &WasmAsmParser::ParseDirectiveSymbolAttribute
>(".internal");
70 &WasmAsmParser::ParseDirectiveSymbolAttribute
>(".hidden");
73 bool error(const StringRef
&Msg
, const AsmToken
&Tok
) {
74 return Parser
->Error(Tok
.getLoc(), Msg
+ Tok
.getString());
77 bool isNext(AsmToken::TokenKind Kind
) {
78 auto Ok
= Lexer
->is(Kind
);
84 bool expect(AsmToken::TokenKind Kind
, const char *KindName
) {
86 return error(std::string("Expected ") + KindName
+ ", instead got: ",
91 bool parseSectionDirectiveText(StringRef
, SMLoc
) {
92 // FIXME: .text currently no-op.
96 bool parseSectionDirectiveData(StringRef
, SMLoc
) {
97 auto *S
= getContext().getObjectFileInfo()->getDataSection();
98 getStreamer().switchSection(S
);
102 uint32_t parseSectionFlags(StringRef FlagStr
, bool &Passive
, bool &Group
) {
104 for (char C
: FlagStr
) {
113 flags
|= wasm::WASM_SEG_FLAG_TLS
;
116 flags
|= wasm::WASM_SEG_FLAG_STRINGS
;
125 bool parseGroup(StringRef
&GroupName
) {
126 if (Lexer
->isNot(AsmToken::Comma
))
127 return TokError("expected group name");
129 if (Lexer
->is(AsmToken::Integer
)) {
130 GroupName
= getTok().getString();
132 } else if (Parser
->parseIdentifier(GroupName
)) {
133 return TokError("invalid group name");
135 if (Lexer
->is(AsmToken::Comma
)) {
138 if (Parser
->parseIdentifier(Linkage
))
139 return TokError("invalid linkage");
140 if (Linkage
!= "comdat")
141 return TokError("Linkage must be 'comdat'");
146 bool parseSectionDirective(StringRef
, SMLoc loc
) {
148 if (Parser
->parseIdentifier(Name
))
149 return TokError("expected identifier in directive");
151 if (expect(AsmToken::Comma
, ","))
154 if (Lexer
->isNot(AsmToken::String
))
155 return error("expected string in directive, instead got: ", Lexer
->getTok());
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());
171 // Update section flags if present in this .section directive
172 bool Passive
= false;
175 parseSectionFlags(getTok().getStringContents(), Passive
, Group
);
177 return TokError("unknown flag");
181 if (expect(AsmToken::Comma
, ",") || expect(AsmToken::At
, "@"))
185 if (Group
&& parseGroup(GroupName
))
188 if (expect(AsmToken::EndOfStatement
, "eol"))
191 // TODO: Parse UniqueID
192 MCSectionWasm
*WS
= getContext().getWasmSection(
193 Name
, *Kind
, Flags
, GroupName
, MCContext::GenericSectionID
);
195 if (WS
->getSegmentFlags() != Flags
)
196 Parser
->Error(loc
, "changed section flags for " + Name
+
198 utohexstr(WS
->getSegmentFlags()));
201 if (!WS
->isWasmData())
202 return Parser
->Error(loc
, "Only data sections can be passive");
206 getStreamer().switchSection(WS
);
210 // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize
211 // so maybe could be shared somehow.
212 bool parseDirectiveSize(StringRef
, SMLoc Loc
) {
214 if (Parser
->parseIdentifier(Name
))
215 return TokError("expected identifier in directive");
216 auto Sym
= getContext().getOrCreateSymbol(Name
);
217 if (expect(AsmToken::Comma
, ","))
220 if (Parser
->parseExpression(Expr
))
222 if (expect(AsmToken::EndOfStatement
, "eol"))
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");
230 getStreamer().emitELFSize(Sym
, Expr
);
235 bool parseDirectiveType(StringRef
, SMLoc
) {
236 // This could be the start of a function, check if followed by
238 if (!Lexer
->is(AsmToken::Identifier
))
239 return error("Expected label after .type directive, got: ",
241 auto WasmSym
= cast
<MCSymbolWasm
>(
242 getStreamer().getContext().getOrCreateSymbol(
243 Lexer
->getTok().getString()));
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
);
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
);
260 return error("Unknown WASM symbol type: ", Lexer
->getTok());
262 return expect(AsmToken::EndOfStatement
, "EOL");
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();
273 if (getLexer().isNot(AsmToken::EndOfStatement
))
274 return TokError("unexpected token in '.ident' directive");
276 getStreamer().emitIdent(Data
);
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
)) {
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
))
301 if (getLexer().isNot(AsmToken::Comma
))
302 return TokError("unexpected token in directive");
311 } // end anonymous namespace
315 MCAsmParserExtension
*createWasmAsmParser() {
316 return new WasmAsmParser
;
319 } // end namespace llvm