1 //===- COFFMasmParser.cpp - COFF MASM 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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/StringSwitch.h"
11 #include "llvm/ADT/Triple.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCDirectives.h"
16 #include "llvm/MC/MCObjectFileInfo.h"
17 #include "llvm/MC/MCParser/MCAsmLexer.h"
18 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
19 #include "llvm/MC/MCParser/MCAsmParserUtils.h"
20 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
21 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/MC/MCSectionCOFF.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/SectionKind.h"
25 #include "llvm/Support/SMLoc.h"
35 class COFFMasmParser : public MCAsmParserExtension {
36 template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
37 void addDirectiveHandler(StringRef Directive) {
38 MCAsmParser::ExtensionDirectiveHandler Handler =
39 std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
40 getParser().addDirectiveHandler(Directive, Handler);
43 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
46 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47 SectionKind Kind, StringRef COMDATSymName,
48 COFF::COMDATType Type);
50 bool ParseDirectiveProc(StringRef, SMLoc);
51 bool ParseDirectiveEndProc(StringRef, SMLoc);
52 bool ParseDirectiveSegment(StringRef, SMLoc);
53 bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
54 bool ParseDirectiveIncludelib(StringRef, SMLoc);
56 bool IgnoreDirective(StringRef, SMLoc) {
57 while (!getLexer().is(AsmToken::EndOfStatement)) {
63 void Initialize(MCAsmParser &Parser) override {
64 // Call the base implementation.
65 MCAsmParserExtension::Initialize(Parser);
76 // Code label directives
80 // Conditional control flow directives
93 // Data allocation directives
106 // Listing control directives
107 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
108 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
109 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
110 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
111 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
112 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
113 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
114 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
115 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
116 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
117 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
118 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
119 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
120 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
130 // Miscellaneous directives
134 addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
145 // Procedure directives
146 addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
147 // invoke (32-bit only)
148 addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
151 // Processor directives
152 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
153 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386P");
154 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
155 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
156 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486P");
157 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
158 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586P");
159 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
160 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686P");
161 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
162 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
163 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
165 // Repeat blocks directives
176 // Segment directives
177 // .alpha (32-bit only, order segments alphabetically)
178 // .dosseg (32-bit only, order segments in DOS convention)
179 // .seq (32-bit only, order segments sequentially)
180 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
181 // group (32-bit only)
182 addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
184 // Simplified segment directives
185 addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
188 &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
190 &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
194 addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
198 // String directives, written <name> <directive> <params>
199 // catstr (equivalent to <name> TEXTEQU <params>)
200 // instr (equivalent to <name> = @InStr(<params>))
201 // sizestr (equivalent to <name> = @SizeStr(<params>))
202 // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
204 // Structure and record directives
212 bool ParseSectionDirectiveCode(StringRef, SMLoc) {
213 return ParseSectionSwitch(".text",
214 COFF::IMAGE_SCN_CNT_CODE
215 | COFF::IMAGE_SCN_MEM_EXECUTE
216 | COFF::IMAGE_SCN_MEM_READ,
217 SectionKind::getText());
220 bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
221 return ParseSectionSwitch(".data",
222 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
223 | COFF::IMAGE_SCN_MEM_READ
224 | COFF::IMAGE_SCN_MEM_WRITE,
225 SectionKind::getData());
228 bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
229 return ParseSectionSwitch(".bss",
230 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
231 | COFF::IMAGE_SCN_MEM_READ
232 | COFF::IMAGE_SCN_MEM_WRITE,
233 SectionKind::getBSS());
236 StringRef CurrentProcedure;
239 COFFMasmParser() = default;
242 } // end anonymous namespace.
244 static SectionKind computeSectionKind(unsigned Flags) {
245 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
246 return SectionKind::getText();
247 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
248 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
249 return SectionKind::getReadOnly();
250 return SectionKind::getData();
253 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
254 unsigned Characteristics,
256 return ParseSectionSwitch(Section, Characteristics, Kind, "",
257 (COFF::COMDATType)0);
260 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
261 unsigned Characteristics,
263 StringRef COMDATSymName,
264 COFF::COMDATType Type) {
265 if (getLexer().isNot(AsmToken::EndOfStatement))
266 return TokError("unexpected token in section switching directive");
269 getStreamer().SwitchSection(getContext().getCOFFSection(
270 Section, Characteristics, Kind, COMDATSymName, Type));
275 bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
276 StringRef SegmentName;
277 if (!getLexer().is(AsmToken::Identifier))
278 return TokError("expected identifier in directive");
279 SegmentName = getTok().getIdentifier();
282 StringRef SectionName = SegmentName;
283 SmallVector<char, 247> SectionNameVector;
284 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
285 COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
286 if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
287 if (SegmentName.size() == 5) {
288 SectionName = ".text";
291 (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
293 Flags = COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE |
294 COFF::IMAGE_SCN_MEM_READ;
296 SectionKind Kind = computeSectionKind(Flags);
297 getStreamer().SwitchSection(getContext().getCOFFSection(
298 SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
302 /// ParseDirectiveSegmentEnd
303 /// ::= identifier "ends"
304 bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
305 StringRef SegmentName;
306 if (!getLexer().is(AsmToken::Identifier))
307 return TokError("expected identifier in directive");
308 SegmentName = getTok().getIdentifier();
310 // Ignore; no action necessary.
315 /// ParseDirectiveIncludelib
316 /// ::= "includelib" identifier
317 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
319 if (getParser().parseIdentifier(Lib))
320 return TokError("expected identifier in includelib directive");
322 unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
323 SectionKind Kind = computeSectionKind(Flags);
324 getStreamer().PushSection();
325 getStreamer().SwitchSection(getContext().getCOFFSection(
326 ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
327 getStreamer().emitBytes("/DEFAULTLIB:");
328 getStreamer().emitBytes(Lib);
329 getStreamer().emitBytes(" ");
330 getStreamer().PopSection();
334 /// ParseDirectiveProc
335 /// TODO(epastor): Implement parameters and other attributes.
336 /// ::= label "proc" [[distance]]
339 bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
341 if (getParser().parseIdentifier(Label))
342 return Error(Loc, "expected identifier for procedure");
343 if (getLexer().is(AsmToken::Identifier)) {
344 StringRef nextVal = getTok().getString();
345 SMLoc nextLoc = getTok().getLoc();
346 if (nextVal.equals_lower("far")) {
347 // TODO(epastor): Handle far procedure definitions.
349 return Error(nextLoc, "far procedure definitions not yet supported");
350 } else if (nextVal.equals_lower("near")) {
352 nextVal = getTok().getString();
353 nextLoc = getTok().getLoc();
356 MCSymbol *Sym = getContext().getOrCreateSymbol(Label);
358 // Define symbol as simple function
359 getStreamer().BeginCOFFSymbolDef(Sym);
360 getStreamer().EmitCOFFSymbolStorageClass(2);
361 getStreamer().EmitCOFFSymbolType(0x20);
362 getStreamer().EndCOFFSymbolDef();
364 getStreamer().emitLabel(Sym, Loc);
365 CurrentProcedure = Label;
368 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
370 SMLoc LabelLoc = getTok().getLoc();
371 if (getParser().parseIdentifier(Label))
372 return Error(LabelLoc, "expected identifier for procedure end");
374 if (CurrentProcedure.empty())
375 return Error(Loc, "endp outside of procedure block");
376 else if (CurrentProcedure != Label)
377 return Error(LabelLoc, "endp does not match current procedure '" +
378 CurrentProcedure + "'");
384 MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
386 } // end namespace llvm