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/Triple.h"
11 #include "llvm/ADT/Twine.h"
12 #include "llvm/BinaryFormat/COFF.h"
13 #include "llvm/MC/MCContext.h"
14 #include "llvm/MC/MCDirectives.h"
15 #include "llvm/MC/MCObjectFileInfo.h"
16 #include "llvm/MC/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
18 #include "llvm/MC/MCParser/MCAsmParserUtils.h"
19 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
20 #include "llvm/MC/MCRegisterInfo.h"
21 #include "llvm/MC/MCSectionCOFF.h"
22 #include "llvm/MC/MCStreamer.h"
23 #include "llvm/MC/MCSymbolCOFF.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 ParseDirectiveAlias(StringRef
, SMLoc
);
58 bool ParseSEHDirectiveAllocStack(StringRef
, SMLoc
);
59 bool ParseSEHDirectiveEndProlog(StringRef
, SMLoc
);
61 bool IgnoreDirective(StringRef
, SMLoc
) {
62 while (!getLexer().is(AsmToken::EndOfStatement
)) {
68 void Initialize(MCAsmParser
&Parser
) override
{
69 // Call the base implementation.
70 MCAsmParserExtension::Initialize(Parser
);
73 addDirectiveHandler
<&COFFMasmParser::ParseSEHDirectiveAllocStack
>(
75 addDirectiveHandler
<&COFFMasmParser::ParseSEHDirectiveEndProlog
>(
78 // Code label directives
82 // Conditional control flow directives
95 // Data allocation directives
103 // Listing control directives
104 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".cref");
105 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".list");
106 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".listall");
107 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".listif");
108 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".listmacro");
109 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".listmacroall");
110 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".nocref");
111 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".nolist");
112 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".nolistif");
113 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".nolistmacro");
114 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>("page");
115 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>("subtitle");
116 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".tfcond");
117 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>("title");
122 // Miscellaneous directives
123 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveAlias
>("alias");
126 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveIncludelib
>(
133 // Procedure directives
134 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveEndProc
>("endp");
135 // invoke (32-bit only)
136 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveProc
>("proc");
139 // Processor directives; all ignored
140 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".386");
141 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".386p");
142 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".387");
143 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".486");
144 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".486p");
145 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".586");
146 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".586p");
147 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".686");
148 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".686p");
149 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".k3d");
150 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".mmx");
151 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".xmm");
157 // Segment directives
158 // .alpha (32-bit only, order segments alphabetically)
159 // .dosseg (32-bit only, order segments in DOS convention)
160 // .seq (32-bit only, order segments sequentially)
161 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveSegmentEnd
>("ends");
162 // group (32-bit only)
163 addDirectiveHandler
<&COFFMasmParser::ParseDirectiveSegment
>("segment");
165 // Simplified segment directives
166 addDirectiveHandler
<&COFFMasmParser::ParseSectionDirectiveCode
>(".code");
169 &COFFMasmParser::ParseSectionDirectiveInitializedData
>(".data");
171 &COFFMasmParser::ParseSectionDirectiveUninitializedData
>(".data?");
175 addDirectiveHandler
<&COFFMasmParser::IgnoreDirective
>(".model");
179 // String directives, written <name> <directive> <params>
180 // catstr (equivalent to <name> TEXTEQU <params>)
181 // instr (equivalent to <name> = @InStr(<params>))
182 // sizestr (equivalent to <name> = @SizeStr(<params>))
183 // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
185 // Structure and record directives
190 bool ParseSectionDirectiveCode(StringRef
, SMLoc
) {
191 return ParseSectionSwitch(".text",
192 COFF::IMAGE_SCN_CNT_CODE
193 | COFF::IMAGE_SCN_MEM_EXECUTE
194 | COFF::IMAGE_SCN_MEM_READ
,
195 SectionKind::getText());
198 bool ParseSectionDirectiveInitializedData(StringRef
, SMLoc
) {
199 return ParseSectionSwitch(".data",
200 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
201 | COFF::IMAGE_SCN_MEM_READ
202 | COFF::IMAGE_SCN_MEM_WRITE
,
203 SectionKind::getData());
206 bool ParseSectionDirectiveUninitializedData(StringRef
, SMLoc
) {
207 return ParseSectionSwitch(".bss",
208 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
209 | COFF::IMAGE_SCN_MEM_READ
210 | COFF::IMAGE_SCN_MEM_WRITE
,
211 SectionKind::getBSS());
214 StringRef CurrentProcedure
;
215 bool CurrentProcedureFramed
;
218 COFFMasmParser() = default;
221 } // end anonymous namespace.
223 static SectionKind
computeSectionKind(unsigned Flags
) {
224 if (Flags
& COFF::IMAGE_SCN_MEM_EXECUTE
)
225 return SectionKind::getText();
226 if (Flags
& COFF::IMAGE_SCN_MEM_READ
&&
227 (Flags
& COFF::IMAGE_SCN_MEM_WRITE
) == 0)
228 return SectionKind::getReadOnly();
229 return SectionKind::getData();
232 bool COFFMasmParser::ParseSectionSwitch(StringRef Section
,
233 unsigned Characteristics
,
235 return ParseSectionSwitch(Section
, Characteristics
, Kind
, "",
236 (COFF::COMDATType
)0);
239 bool COFFMasmParser::ParseSectionSwitch(StringRef Section
,
240 unsigned Characteristics
,
242 StringRef COMDATSymName
,
243 COFF::COMDATType Type
) {
244 if (getLexer().isNot(AsmToken::EndOfStatement
))
245 return TokError("unexpected token in section switching directive");
248 getStreamer().SwitchSection(getContext().getCOFFSection(
249 Section
, Characteristics
, Kind
, COMDATSymName
, Type
));
254 bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive
, SMLoc Loc
) {
255 StringRef SegmentName
;
256 if (!getLexer().is(AsmToken::Identifier
))
257 return TokError("expected identifier in directive");
258 SegmentName
= getTok().getIdentifier();
261 StringRef SectionName
= SegmentName
;
262 SmallVector
<char, 247> SectionNameVector
;
263 unsigned Flags
= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
|
264 COFF::IMAGE_SCN_MEM_READ
| COFF::IMAGE_SCN_MEM_WRITE
;
265 if (SegmentName
== "_TEXT" || SegmentName
.startswith("_TEXT$")) {
266 if (SegmentName
.size() == 5) {
267 SectionName
= ".text";
270 (".text$" + SegmentName
.substr(6)).toStringRef(SectionNameVector
);
272 Flags
= COFF::IMAGE_SCN_CNT_CODE
| COFF::IMAGE_SCN_MEM_EXECUTE
|
273 COFF::IMAGE_SCN_MEM_READ
;
275 SectionKind Kind
= computeSectionKind(Flags
);
276 getStreamer().SwitchSection(getContext().getCOFFSection(
277 SectionName
, Flags
, Kind
, "", (COFF::COMDATType
)(0)));
281 /// ParseDirectiveSegmentEnd
282 /// ::= identifier "ends"
283 bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive
, SMLoc Loc
) {
284 StringRef SegmentName
;
285 if (!getLexer().is(AsmToken::Identifier
))
286 return TokError("expected identifier in directive");
287 SegmentName
= getTok().getIdentifier();
289 // Ignore; no action necessary.
294 /// ParseDirectiveIncludelib
295 /// ::= "includelib" identifier
296 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive
, SMLoc Loc
) {
298 if (getParser().parseIdentifier(Lib
))
299 return TokError("expected identifier in includelib directive");
301 unsigned Flags
= COFF::IMAGE_SCN_MEM_PRELOAD
| COFF::IMAGE_SCN_MEM_16BIT
;
302 SectionKind Kind
= computeSectionKind(Flags
);
303 getStreamer().PushSection();
304 getStreamer().SwitchSection(getContext().getCOFFSection(
305 ".drectve", Flags
, Kind
, "", (COFF::COMDATType
)(0)));
306 getStreamer().emitBytes("/DEFAULTLIB:");
307 getStreamer().emitBytes(Lib
);
308 getStreamer().emitBytes(" ");
309 getStreamer().PopSection();
313 /// ParseDirectiveProc
314 /// TODO(epastor): Implement parameters and other attributes.
315 /// ::= label "proc" [[distance]]
318 bool COFFMasmParser::ParseDirectiveProc(StringRef Directive
, SMLoc Loc
) {
320 if (getParser().parseIdentifier(Label
))
321 return Error(Loc
, "expected identifier for procedure");
322 if (getLexer().is(AsmToken::Identifier
)) {
323 StringRef nextVal
= getTok().getString();
324 SMLoc nextLoc
= getTok().getLoc();
325 if (nextVal
.equals_insensitive("far")) {
326 // TODO(epastor): Handle far procedure definitions.
328 return Error(nextLoc
, "far procedure definitions not yet supported");
329 } else if (nextVal
.equals_insensitive("near")) {
331 nextVal
= getTok().getString();
332 nextLoc
= getTok().getLoc();
335 MCSymbolCOFF
*Sym
= cast
<MCSymbolCOFF
>(getContext().getOrCreateSymbol(Label
));
337 // Define symbol as simple external function
338 Sym
->setExternal(true);
339 Sym
->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
<< COFF::SCT_COMPLEX_TYPE_SHIFT
);
342 if (getLexer().is(AsmToken::Identifier
) &&
343 getTok().getString().equals_insensitive("frame")) {
346 getStreamer().EmitWinCFIStartProc(Sym
, Loc
);
348 getStreamer().emitLabel(Sym
, Loc
);
350 CurrentProcedure
= Label
;
351 CurrentProcedureFramed
= Framed
;
354 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive
, SMLoc Loc
) {
356 SMLoc LabelLoc
= getTok().getLoc();
357 if (getParser().parseIdentifier(Label
))
358 return Error(LabelLoc
, "expected identifier for procedure end");
360 if (CurrentProcedure
.empty())
361 return Error(Loc
, "endp outside of procedure block");
362 else if (CurrentProcedure
!= Label
)
363 return Error(LabelLoc
, "endp does not match current procedure '" +
364 CurrentProcedure
+ "'");
366 if (CurrentProcedureFramed
) {
367 getStreamer().EmitWinCFIEndProc(Loc
);
369 CurrentProcedure
= "";
370 CurrentProcedureFramed
= false;
374 bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive
, SMLoc Loc
) {
375 std::string AliasName
, ActualName
;
376 if (getTok().isNot(AsmToken::Less
) ||
377 getParser().parseAngleBracketString(AliasName
))
378 return Error(getTok().getLoc(), "expected <aliasName>");
379 if (getParser().parseToken(AsmToken::Equal
))
380 return addErrorSuffix(" in " + Directive
+ " directive");
381 if (getTok().isNot(AsmToken::Less
) ||
382 getParser().parseAngleBracketString(ActualName
))
383 return Error(getTok().getLoc(), "expected <actualName>");
385 MCSymbol
*Alias
= getContext().getOrCreateSymbol(AliasName
);
386 MCSymbol
*Actual
= getContext().getOrCreateSymbol(ActualName
);
388 getStreamer().emitWeakReference(Alias
, Actual
);
393 bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive
,
396 SMLoc SizeLoc
= getTok().getLoc();
397 if (getParser().parseAbsoluteExpression(Size
))
398 return Error(SizeLoc
, "expected integer size");
400 return Error(SizeLoc
, "stack size must be a multiple of 8");
401 getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size
), Loc
);
405 bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive
,
407 getStreamer().EmitWinCFIEndProlog(Loc
);
413 MCAsmParserExtension
*createCOFFMasmParser() { return new COFFMasmParser
; }
415 } // end namespace llvm