COFFMasmParser.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. //===- COFFMasmParser.cpp - COFF MASM 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. #include "llvm/ADT/StringRef.h"
  9. #include "llvm/ADT/Triple.h"
  10. #include "llvm/ADT/Twine.h"
  11. #include "llvm/BinaryFormat/COFF.h"
  12. #include "llvm/MC/MCContext.h"
  13. #include "llvm/MC/MCDirectives.h"
  14. #include "llvm/MC/MCObjectFileInfo.h"
  15. #include "llvm/MC/MCParser/MCAsmLexer.h"
  16. #include "llvm/MC/MCParser/MCAsmParserExtension.h"
  17. #include "llvm/MC/MCParser/MCAsmParserUtils.h"
  18. #include "llvm/MC/MCParser/MCTargetAsmParser.h"
  19. #include "llvm/MC/MCRegisterInfo.h"
  20. #include "llvm/MC/MCSectionCOFF.h"
  21. #include "llvm/MC/MCStreamer.h"
  22. #include "llvm/MC/MCSymbolCOFF.h"
  23. #include "llvm/MC/SectionKind.h"
  24. #include "llvm/Support/SMLoc.h"
  25. #include <cassert>
  26. #include <cstdint>
  27. #include <limits>
  28. #include <utility>
  29. using namespace llvm;
  30. namespace {
  31. class COFFMasmParser : public MCAsmParserExtension {
  32. template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
  33. void addDirectiveHandler(StringRef Directive) {
  34. MCAsmParser::ExtensionDirectiveHandler Handler =
  35. std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
  36. getParser().addDirectiveHandler(Directive, Handler);
  37. }
  38. bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
  39. SectionKind Kind);
  40. bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
  41. SectionKind Kind, StringRef COMDATSymName,
  42. COFF::COMDATType Type);
  43. bool ParseDirectiveProc(StringRef, SMLoc);
  44. bool ParseDirectiveEndProc(StringRef, SMLoc);
  45. bool ParseDirectiveSegment(StringRef, SMLoc);
  46. bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
  47. bool ParseDirectiveIncludelib(StringRef, SMLoc);
  48. bool ParseDirectiveAlias(StringRef, SMLoc);
  49. bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
  50. bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
  51. bool IgnoreDirective(StringRef, SMLoc) {
  52. while (!getLexer().is(AsmToken::EndOfStatement)) {
  53. Lex();
  54. }
  55. return false;
  56. }
  57. void Initialize(MCAsmParser &Parser) override {
  58. // Call the base implementation.
  59. MCAsmParserExtension::Initialize(Parser);
  60. // x64 directives
  61. addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
  62. ".allocstack");
  63. addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
  64. ".endprolog");
  65. // Code label directives
  66. // label
  67. // org
  68. // Conditional control flow directives
  69. // .break
  70. // .continue
  71. // .else
  72. // .elseif
  73. // .endif
  74. // .endw
  75. // .if
  76. // .repeat
  77. // .until
  78. // .untilcxz
  79. // .while
  80. // Data allocation directives
  81. // align
  82. // even
  83. // mmword
  84. // tbyte
  85. // xmmword
  86. // ymmword
  87. // Listing control directives
  88. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
  89. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
  90. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
  91. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
  92. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
  93. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
  94. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
  95. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
  96. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
  97. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
  98. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
  99. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
  100. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
  101. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
  102. // Macro directives
  103. // goto
  104. // Miscellaneous directives
  105. addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
  106. // assume
  107. // .fpo
  108. addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
  109. "includelib");
  110. // option
  111. // popcontext
  112. // pushcontext
  113. // .safeseh
  114. // Procedure directives
  115. addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
  116. // invoke (32-bit only)
  117. addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
  118. // proto
  119. // Processor directives; all ignored
  120. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
  121. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386p");
  122. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
  123. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
  124. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486p");
  125. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
  126. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586p");
  127. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
  128. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686p");
  129. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
  130. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
  131. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
  132. // Scope directives
  133. // comm
  134. // externdef
  135. // Segment directives
  136. // .alpha (32-bit only, order segments alphabetically)
  137. // .dosseg (32-bit only, order segments in DOS convention)
  138. // .seq (32-bit only, order segments sequentially)
  139. addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
  140. // group (32-bit only)
  141. addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
  142. // Simplified segment directives
  143. addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
  144. // .const
  145. addDirectiveHandler<
  146. &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
  147. addDirectiveHandler<
  148. &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
  149. // .exit
  150. // .fardata
  151. // .fardata?
  152. addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
  153. // .stack
  154. // .startup
  155. // String directives, written <name> <directive> <params>
  156. // catstr (equivalent to <name> TEXTEQU <params>)
  157. // instr (equivalent to <name> = @InStr(<params>))
  158. // sizestr (equivalent to <name> = @SizeStr(<params>))
  159. // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
  160. // Structure and record directives
  161. // record
  162. // typedef
  163. }
  164. bool ParseSectionDirectiveCode(StringRef, SMLoc) {
  165. return ParseSectionSwitch(".text",
  166. COFF::IMAGE_SCN_CNT_CODE
  167. | COFF::IMAGE_SCN_MEM_EXECUTE
  168. | COFF::IMAGE_SCN_MEM_READ,
  169. SectionKind::getText());
  170. }
  171. bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
  172. return ParseSectionSwitch(".data",
  173. COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
  174. | COFF::IMAGE_SCN_MEM_READ
  175. | COFF::IMAGE_SCN_MEM_WRITE,
  176. SectionKind::getData());
  177. }
  178. bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
  179. return ParseSectionSwitch(".bss",
  180. COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
  181. | COFF::IMAGE_SCN_MEM_READ
  182. | COFF::IMAGE_SCN_MEM_WRITE,
  183. SectionKind::getBSS());
  184. }
  185. StringRef CurrentProcedure;
  186. bool CurrentProcedureFramed;
  187. public:
  188. COFFMasmParser() = default;
  189. };
  190. } // end anonymous namespace.
  191. static SectionKind computeSectionKind(unsigned Flags) {
  192. if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
  193. return SectionKind::getText();
  194. if (Flags & COFF::IMAGE_SCN_MEM_READ &&
  195. (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
  196. return SectionKind::getReadOnly();
  197. return SectionKind::getData();
  198. }
  199. bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
  200. unsigned Characteristics,
  201. SectionKind Kind) {
  202. return ParseSectionSwitch(Section, Characteristics, Kind, "",
  203. (COFF::COMDATType)0);
  204. }
  205. bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
  206. unsigned Characteristics,
  207. SectionKind Kind,
  208. StringRef COMDATSymName,
  209. COFF::COMDATType Type) {
  210. if (getLexer().isNot(AsmToken::EndOfStatement))
  211. return TokError("unexpected token in section switching directive");
  212. Lex();
  213. getStreamer().SwitchSection(getContext().getCOFFSection(
  214. Section, Characteristics, Kind, COMDATSymName, Type));
  215. return false;
  216. }
  217. bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
  218. StringRef SegmentName;
  219. if (!getLexer().is(AsmToken::Identifier))
  220. return TokError("expected identifier in directive");
  221. SegmentName = getTok().getIdentifier();
  222. Lex();
  223. StringRef SectionName = SegmentName;
  224. SmallVector<char, 247> SectionNameVector;
  225. unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
  226. COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
  227. if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
  228. if (SegmentName.size() == 5) {
  229. SectionName = ".text";
  230. } else {
  231. SectionName =
  232. (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
  233. }
  234. Flags = COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE |
  235. COFF::IMAGE_SCN_MEM_READ;
  236. }
  237. SectionKind Kind = computeSectionKind(Flags);
  238. getStreamer().SwitchSection(getContext().getCOFFSection(
  239. SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
  240. return false;
  241. }
  242. /// ParseDirectiveSegmentEnd
  243. /// ::= identifier "ends"
  244. bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
  245. StringRef SegmentName;
  246. if (!getLexer().is(AsmToken::Identifier))
  247. return TokError("expected identifier in directive");
  248. SegmentName = getTok().getIdentifier();
  249. // Ignore; no action necessary.
  250. Lex();
  251. return false;
  252. }
  253. /// ParseDirectiveIncludelib
  254. /// ::= "includelib" identifier
  255. bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
  256. StringRef Lib;
  257. if (getParser().parseIdentifier(Lib))
  258. return TokError("expected identifier in includelib directive");
  259. unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
  260. SectionKind Kind = computeSectionKind(Flags);
  261. getStreamer().PushSection();
  262. getStreamer().SwitchSection(getContext().getCOFFSection(
  263. ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
  264. getStreamer().emitBytes("/DEFAULTLIB:");
  265. getStreamer().emitBytes(Lib);
  266. getStreamer().emitBytes(" ");
  267. getStreamer().PopSection();
  268. return false;
  269. }
  270. /// ParseDirectiveProc
  271. /// TODO(epastor): Implement parameters and other attributes.
  272. /// ::= label "proc" [[distance]]
  273. /// statements
  274. /// label "endproc"
  275. bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
  276. StringRef Label;
  277. if (getParser().parseIdentifier(Label))
  278. return Error(Loc, "expected identifier for procedure");
  279. if (getLexer().is(AsmToken::Identifier)) {
  280. StringRef nextVal = getTok().getString();
  281. SMLoc nextLoc = getTok().getLoc();
  282. if (nextVal.equals_insensitive("far")) {
  283. // TODO(epastor): Handle far procedure definitions.
  284. Lex();
  285. return Error(nextLoc, "far procedure definitions not yet supported");
  286. } else if (nextVal.equals_insensitive("near")) {
  287. Lex();
  288. nextVal = getTok().getString();
  289. nextLoc = getTok().getLoc();
  290. }
  291. }
  292. MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
  293. // Define symbol as simple external function
  294. Sym->setExternal(true);
  295. Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
  296. bool Framed = false;
  297. if (getLexer().is(AsmToken::Identifier) &&
  298. getTok().getString().equals_insensitive("frame")) {
  299. Lex();
  300. Framed = true;
  301. getStreamer().EmitWinCFIStartProc(Sym, Loc);
  302. }
  303. getStreamer().emitLabel(Sym, Loc);
  304. CurrentProcedure = Label;
  305. CurrentProcedureFramed = Framed;
  306. return false;
  307. }
  308. bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
  309. StringRef Label;
  310. SMLoc LabelLoc = getTok().getLoc();
  311. if (getParser().parseIdentifier(Label))
  312. return Error(LabelLoc, "expected identifier for procedure end");
  313. if (CurrentProcedure.empty())
  314. return Error(Loc, "endp outside of procedure block");
  315. else if (CurrentProcedure != Label)
  316. return Error(LabelLoc, "endp does not match current procedure '" +
  317. CurrentProcedure + "'");
  318. if (CurrentProcedureFramed) {
  319. getStreamer().EmitWinCFIEndProc(Loc);
  320. }
  321. CurrentProcedure = "";
  322. CurrentProcedureFramed = false;
  323. return false;
  324. }
  325. bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
  326. std::string AliasName, ActualName;
  327. if (getTok().isNot(AsmToken::Less) ||
  328. getParser().parseAngleBracketString(AliasName))
  329. return Error(getTok().getLoc(), "expected <aliasName>");
  330. if (getParser().parseToken(AsmToken::Equal))
  331. return addErrorSuffix(" in " + Directive + " directive");
  332. if (getTok().isNot(AsmToken::Less) ||
  333. getParser().parseAngleBracketString(ActualName))
  334. return Error(getTok().getLoc(), "expected <actualName>");
  335. MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
  336. MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
  337. getStreamer().emitWeakReference(Alias, Actual);
  338. return false;
  339. }
  340. bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
  341. SMLoc Loc) {
  342. int64_t Size;
  343. SMLoc SizeLoc = getTok().getLoc();
  344. if (getParser().parseAbsoluteExpression(Size))
  345. return Error(SizeLoc, "expected integer size");
  346. if (Size % 8 != 0)
  347. return Error(SizeLoc, "stack size must be a multiple of 8");
  348. getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
  349. return false;
  350. }
  351. bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
  352. SMLoc Loc) {
  353. getStreamer().EmitWinCFIEndProlog(Loc);
  354. return false;
  355. }
  356. namespace llvm {
  357. MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
  358. } // end namespace llvm