WasmAsmParser.cpp 11 KB

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