LLVM  15.0.0git
COFFMasmParser.cpp
Go to the documentation of this file.
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 
9 #include "llvm/ADT/StringRef.h"
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/BinaryFormat/COFF.h"
12 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCSectionCOFF.h"
16 #include "llvm/MC/MCStreamer.h"
17 #include "llvm/MC/MCSymbolCOFF.h"
18 #include "llvm/MC/SectionKind.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/SMLoc.h"
21 #include <cstdint>
22 #include <utility>
23 
24 using namespace llvm;
25 
26 namespace {
27 
28 class COFFMasmParser : public MCAsmParserExtension {
29  template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
30  void addDirectiveHandler(StringRef Directive) {
32  std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
33  getParser().addDirectiveHandler(Directive, Handler);
34  }
35 
36  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
38 
39  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
40  SectionKind Kind, StringRef COMDATSymName,
42 
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 
49  bool ParseDirectiveAlias(StringRef, SMLoc);
50 
51  bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
52  bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
53 
54  bool IgnoreDirective(StringRef, SMLoc) {
55  while (!getLexer().is(AsmToken::EndOfStatement)) {
56  Lex();
57  }
58  return false;
59  }
60 
61  void Initialize(MCAsmParser &Parser) override {
62  // Call the base implementation.
64 
65  // x64 directives
66  addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
67  ".allocstack");
68  addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
69  ".endprolog");
70 
71  // Code label directives
72  // label
73  // org
74 
75  // Conditional control flow directives
76  // .break
77  // .continue
78  // .else
79  // .elseif
80  // .endif
81  // .endw
82  // .if
83  // .repeat
84  // .until
85  // .untilcxz
86  // .while
87 
88  // Data allocation directives
89  // align
90  // even
91  // mmword
92  // tbyte
93  // xmmword
94  // ymmword
95 
96  // Listing control directives
97  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
98  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
99  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
100  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
101  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
102  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
103  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
104  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
105  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
106  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
107  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
108  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
109  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
110  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
111 
112  // Macro directives
113  // goto
114 
115  // Miscellaneous directives
116  addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
117  // assume
118  // .fpo
119  addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
120  "includelib");
121  // option
122  // popcontext
123  // pushcontext
124  // .safeseh
125 
126  // Procedure directives
127  addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
128  // invoke (32-bit only)
129  addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
130  // proto
131 
132  // Processor directives; all ignored
133  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
134  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386p");
135  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
136  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
137  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486p");
138  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
139  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586p");
140  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
141  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686p");
142  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
143  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
144  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
145 
146  // Scope directives
147  // comm
148  // externdef
149 
150  // Segment directives
151  // .alpha (32-bit only, order segments alphabetically)
152  // .dosseg (32-bit only, order segments in DOS convention)
153  // .seq (32-bit only, order segments sequentially)
154  addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
155  // group (32-bit only)
156  addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
157 
158  // Simplified segment directives
159  addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
160  // .const
161  addDirectiveHandler<
162  &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
163  addDirectiveHandler<
164  &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
165  // .exit
166  // .fardata
167  // .fardata?
168  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
169  // .stack
170  // .startup
171 
172  // String directives, written <name> <directive> <params>
173  // catstr (equivalent to <name> TEXTEQU <params>)
174  // instr (equivalent to <name> = @InStr(<params>))
175  // sizestr (equivalent to <name> = @SizeStr(<params>))
176  // substr (equivalent to <name> TEXTEQU @SubStr(<params>))
177 
178  // Structure and record directives
179  // record
180  // typedef
181  }
182 
183  bool ParseSectionDirectiveCode(StringRef, SMLoc) {
184  return ParseSectionSwitch(".text",
189  }
190 
191  bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
192  return ParseSectionSwitch(".data",
197  }
198 
199  bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
200  return ParseSectionSwitch(".bss",
205  }
206 
207  StringRef CurrentProcedure;
208  bool CurrentProcedureFramed;
209 
210 public:
211  COFFMasmParser() = default;
212 };
213 
214 } // end anonymous namespace.
215 
216 static SectionKind computeSectionKind(unsigned Flags) {
217  if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
218  return SectionKind::getText();
219  if (Flags & COFF::IMAGE_SCN_MEM_READ &&
220  (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
221  return SectionKind::getReadOnly();
222  return SectionKind::getData();
223 }
224 
225 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
226  unsigned Characteristics,
227  SectionKind Kind) {
228  return ParseSectionSwitch(Section, Characteristics, Kind, "",
229  (COFF::COMDATType)0);
230 }
231 
232 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
233  unsigned Characteristics,
235  StringRef COMDATSymName,
237  if (getLexer().isNot(AsmToken::EndOfStatement))
238  return TokError("unexpected token in section switching directive");
239  Lex();
240 
241  getStreamer().SwitchSection(getContext().getCOFFSection(
242  Section, Characteristics, Kind, COMDATSymName, Type));
243 
244  return false;
245 }
246 
247 bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
248  StringRef SegmentName;
249  if (!getLexer().is(AsmToken::Identifier))
250  return TokError("expected identifier in directive");
251  SegmentName = getTok().getIdentifier();
252  Lex();
253 
254  StringRef SectionName = SegmentName;
255  SmallVector<char, 247> SectionNameVector;
256  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
258  if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
259  if (SegmentName.size() == 5) {
260  SectionName = ".text";
261  } else {
262  SectionName =
263  (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
264  }
267  }
269  getStreamer().SwitchSection(getContext().getCOFFSection(
270  SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
271  return false;
272 }
273 
274 /// ParseDirectiveSegmentEnd
275 /// ::= identifier "ends"
276 bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
277  StringRef SegmentName;
278  if (!getLexer().is(AsmToken::Identifier))
279  return TokError("expected identifier in directive");
280  SegmentName = getTok().getIdentifier();
281 
282  // Ignore; no action necessary.
283  Lex();
284  return false;
285 }
286 
287 /// ParseDirectiveIncludelib
288 /// ::= "includelib" identifier
289 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
290  StringRef Lib;
291  if (getParser().parseIdentifier(Lib))
292  return TokError("expected identifier in includelib directive");
293 
296  getStreamer().PushSection();
297  getStreamer().SwitchSection(getContext().getCOFFSection(
298  ".drectve", Flags, Kind, "", (COFF::COMDATType)(0)));
299  getStreamer().emitBytes("/DEFAULTLIB:");
300  getStreamer().emitBytes(Lib);
301  getStreamer().emitBytes(" ");
302  getStreamer().PopSection();
303  return false;
304 }
305 
306 /// ParseDirectiveProc
307 /// TODO(epastor): Implement parameters and other attributes.
308 /// ::= label "proc" [[distance]]
309 /// statements
310 /// label "endproc"
311 bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
313  if (getParser().parseIdentifier(Label))
314  return Error(Loc, "expected identifier for procedure");
315  if (getLexer().is(AsmToken::Identifier)) {
316  StringRef nextVal = getTok().getString();
317  SMLoc nextLoc = getTok().getLoc();
318  if (nextVal.equals_insensitive("far")) {
319  // TODO(epastor): Handle far procedure definitions.
320  Lex();
321  return Error(nextLoc, "far procedure definitions not yet supported");
322  } else if (nextVal.equals_insensitive("near")) {
323  Lex();
324  nextVal = getTok().getString();
325  nextLoc = getTok().getLoc();
326  }
327  }
328  MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
329 
330  // Define symbol as simple external function
331  Sym->setExternal(true);
333 
334  bool Framed = false;
335  if (getLexer().is(AsmToken::Identifier) &&
336  getTok().getString().equals_insensitive("frame")) {
337  Lex();
338  Framed = true;
339  getStreamer().EmitWinCFIStartProc(Sym, Loc);
340  }
341  getStreamer().emitLabel(Sym, Loc);
342 
343  CurrentProcedure = Label;
344  CurrentProcedureFramed = Framed;
345  return false;
346 }
347 bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
349  SMLoc LabelLoc = getTok().getLoc();
350  if (getParser().parseIdentifier(Label))
351  return Error(LabelLoc, "expected identifier for procedure end");
352 
353  if (CurrentProcedure.empty())
354  return Error(Loc, "endp outside of procedure block");
355  else if (CurrentProcedure != Label)
356  return Error(LabelLoc, "endp does not match current procedure '" +
357  CurrentProcedure + "'");
358 
359  if (CurrentProcedureFramed) {
360  getStreamer().EmitWinCFIEndProc(Loc);
361  }
362  CurrentProcedure = "";
363  CurrentProcedureFramed = false;
364  return false;
365 }
366 
367 bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
368  std::string AliasName, ActualName;
369  if (getTok().isNot(AsmToken::Less) ||
370  getParser().parseAngleBracketString(AliasName))
371  return Error(getTok().getLoc(), "expected <aliasName>");
372  if (getParser().parseToken(AsmToken::Equal))
373  return addErrorSuffix(" in " + Directive + " directive");
374  if (getTok().isNot(AsmToken::Less) ||
375  getParser().parseAngleBracketString(ActualName))
376  return Error(getTok().getLoc(), "expected <actualName>");
377 
378  MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
379  MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
380 
381  getStreamer().emitWeakReference(Alias, Actual);
382 
383  return false;
384 }
385 
386 bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
387  SMLoc Loc) {
388  int64_t Size;
389  SMLoc SizeLoc = getTok().getLoc();
390  if (getParser().parseAbsoluteExpression(Size))
391  return Error(SizeLoc, "expected integer size");
392  if (Size % 8 != 0)
393  return Error(SizeLoc, "stack size must be a multiple of 8");
394  getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
395  return false;
396 }
397 
398 bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
399  SMLoc Loc) {
400  getStreamer().EmitWinCFIEndProlog(Loc);
401  return false;
402 }
403 
404 namespace llvm {
405 
406 MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
407 
408 } // end namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:76
llvm::MCAsmParser
Generic assembler parser interface, for use by target specific assembly parsers.
Definition: MCAsmParser.h:124
is
should just be implemented with a CLZ instruction Since there are other e that share this it would be best to implement this in a target independent as zero is the default value for the binary encoder e add r0 add r5 Register operands should be distinct That is
Definition: README.txt:725
llvm::StringRef::startswith
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:286
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
@ IMAGE_SCN_CNT_UNINITIALIZED_DATA
Definition: COFF.h:289
llvm::MCSymbol
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
StringRef.h
llvm::AsmToken::EndOfStatement
@ EndOfStatement
Definition: MCAsmMacro.h:42
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
MCSectionCOFF.h
llvm::COFF::SCT_COMPLEX_TYPE_SHIFT
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
Definition: COFF.h:264
COFF.h
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
llvm::COFF::COMDATType
COMDATType
Definition: COFF.h:405
llvm::StringRef::substr
LLVM_NODISCARD StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
Definition: StringRef.h:611
llvm::SectionKind::getReadOnly
static SectionKind getReadOnly()
Definition: SectionKind.h:192
llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
@ IMAGE_SCN_CNT_INITIALIZED_DATA
Definition: COFF.h:288
llvm::SMLoc
Represents a location in source code.
Definition: SMLoc.h:23
Twine.h
MCContext.h
llvm::COFF::IMAGE_SCN_MEM_READ
@ IMAGE_SCN_MEM_READ
Definition: COFF.h:320
llvm::SubDirectoryType::Lib
@ Lib
llvm::SectionKind::getBSS
static SectionKind getBSS()
Definition: SectionKind.h:209
llvm::MCAsmParser::ExtensionDirectiveHandler
std::pair< MCAsmParserExtension *, DirectiveHandler > ExtensionDirectiveHandler
Definition: MCAsmParser.h:128
llvm::dwarf::toStringRef
StringRef toStringRef(const Optional< DWARFFormValue > &V, StringRef Default={})
Take an optional DWARFFormValue and try to extract a string value from it.
Definition: DWARFFormValue.h:193
llvm::MCSymbolCOFF
Definition: MCSymbolCOFF.h:17
SMLoc.h
llvm::SectionKind::getText
static SectionKind getText()
Definition: SectionKind.h:190
isNot
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
Definition: AMDGPULegalizerInfo.cpp:2886
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
llvm::MCSymbolCOFF::setType
void setType(uint16_t Ty) const
Definition: MCSymbolCOFF.h:36
llvm::AsmToken::Equal
@ Equal
Definition: MCAsmMacro.h:49
MCAsmLexer.h
llvm::StringRef::equals_insensitive
LLVM_NODISCARD bool equals_insensitive(StringRef RHS) const
Check for string equality, ignoring case.
Definition: StringRef.h:194
llvm::MCAsmParserExtension::Initialize
virtual void Initialize(MCAsmParser &Parser)
Initialize the extension for parsing using the given Parser.
Definition: MCAsmParserExtension.cpp:21
llvm::AsmToken::Less
@ Less
Definition: MCAsmMacro.h:53
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::MCAsmParserExtension
Generic interface for extending the MCAsmParser, which is implemented by target and object file assem...
Definition: MCAsmParserExtension.h:24
llvm::SectionKind::getData
static SectionKind getData()
Definition: SectionKind.h:213
llvm::StringRef::size
constexpr LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:157
llvm::MCSymbol::setExternal
void setExternal(bool Value) const
Definition: MCSymbol.h:402
llvm::SectionKind
SectionKind - This is a simple POD value that classifies the properties of a section.
Definition: SectionKind.h:22
llvm::pdb::PDB_SymType::Label
@ Label
llvm::AsmToken::Identifier
@ Identifier
Definition: MCAsmMacro.h:28
MCAsmParserExtension.h
llvm::COFF::IMAGE_SCN_MEM_PRELOAD
@ IMAGE_SCN_MEM_PRELOAD
Definition: COFF.h:298
llvm::SectionName
Definition: DWARFSection.h:21
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::COFF::IMAGE_SCN_CNT_CODE
@ IMAGE_SCN_CNT_CODE
Definition: COFF.h:287
Casting.h
MCSymbolCOFF.h
SectionKind.h
computeSectionKind
static SectionKind computeSectionKind(unsigned Flags)
Definition: COFFMasmParser.cpp:216
MCStreamer.h
Characteristics
COFFYAML::WeakExternalCharacteristics Characteristics
Definition: COFFYAML.cpp:329
llvm::COFF::IMAGE_SCN_MEM_EXECUTE
@ IMAGE_SCN_MEM_EXECUTE
Definition: COFF.h:319
llvm::COFF::IMAGE_SCN_MEM_16BIT
@ IMAGE_SCN_MEM_16BIT
Definition: COFF.h:296
llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
Definition: COFF.h:260
llvm::Directive
Definition: DirectiveEmitter.h:100
llvm::COFF::IMAGE_SCN_MEM_WRITE
@ IMAGE_SCN_MEM_WRITE
Definition: COFF.h:321
llvm::createCOFFMasmParser
MCAsmParserExtension * createCOFFMasmParser()
Definition: COFFMasmParser.cpp:406