LLVM  13.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/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"
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"
26 #include <cassert>
27 #include <cstdint>
28 #include <limits>
29 #include <utility>
30 
31 using namespace llvm;
32 
33 namespace {
34 
35 class COFFMasmParser : public MCAsmParserExtension {
36  template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
37  void addDirectiveHandler(StringRef Directive) {
39  std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
40  getParser().addDirectiveHandler(Directive, Handler);
41  }
42 
43  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
45 
46  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47  SectionKind Kind, StringRef COMDATSymName,
49 
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);
55 
56  bool ParseDirectiveAlias(StringRef, SMLoc);
57 
58  bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
59  bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
60 
61  bool IgnoreDirective(StringRef, SMLoc) {
62  while (!getLexer().is(AsmToken::EndOfStatement)) {
63  Lex();
64  }
65  return false;
66  }
67 
68  void Initialize(MCAsmParser &Parser) override {
69  // Call the base implementation.
71 
72  // x64 directives
73  addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
74  ".allocstack");
75  addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
76  ".endprolog");
77 
78  // Code label directives
79  // label
80  // org
81 
82  // Conditional control flow directives
83  // .break
84  // .continue
85  // .else
86  // .elseif
87  // .endif
88  // .endw
89  // .if
90  // .repeat
91  // .until
92  // .untilcxz
93  // .while
94 
95  // Data allocation directives
96  // align
97  // even
98  // mmword
99  // tbyte
100  // xmmword
101  // ymmword
102 
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");
118 
119  // Macro directives
120  // goto
121 
122  // Miscellaneous directives
123  addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
124  // assume
125  // .fpo
126  addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
127  "includelib");
128  // option
129  // popcontext
130  // pushcontext
131  // .safeseh
132 
133  // Procedure directives
134  addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
135  // invoke (32-bit only)
136  addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
137  // proto
138 
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");
152 
153  // Scope directives
154  // comm
155  // externdef
156 
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");
164 
165  // Simplified segment directives
166  addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
167  // .const
168  addDirectiveHandler<
169  &COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
170  addDirectiveHandler<
171  &COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
172  // .exit
173  // .fardata
174  // .fardata?
175  addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
176  // .stack
177  // .startup
178 
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>))
184 
185  // Structure and record directives
186  // record
187  // typedef
188  }
189 
190  bool ParseSectionDirectiveCode(StringRef, SMLoc) {
191  return ParseSectionSwitch(".text",
196  }
197 
198  bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
199  return ParseSectionSwitch(".data",
204  }
205 
206  bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
207  return ParseSectionSwitch(".bss",
212  }
213 
214  StringRef CurrentProcedure;
215  bool CurrentProcedureFramed;
216 
217 public:
218  COFFMasmParser() = default;
219 };
220 
221 } // end anonymous namespace.
222 
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();
230 }
231 
232 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
233  unsigned Characteristics,
234  SectionKind Kind) {
235  return ParseSectionSwitch(Section, Characteristics, Kind, "",
236  (COFF::COMDATType)0);
237 }
238 
239 bool COFFMasmParser::ParseSectionSwitch(StringRef Section,
240  unsigned Characteristics,
242  StringRef COMDATSymName,
244  if (getLexer().isNot(AsmToken::EndOfStatement))
245  return TokError("unexpected token in section switching directive");
246  Lex();
247 
248  getStreamer().SwitchSection(getContext().getCOFFSection(
249  Section, Characteristics, Kind, COMDATSymName, Type));
250 
251  return false;
252 }
253 
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();
259  Lex();
260 
261  StringRef SectionName = SegmentName;
262  SmallVector<char, 247> SectionNameVector;
263  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
265  if (SegmentName == "_TEXT" || SegmentName.startswith("_TEXT$")) {
266  if (SegmentName.size() == 5) {
267  SectionName = ".text";
268  } else {
269  SectionName =
270  (".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
271  }
274  }
276  getStreamer().SwitchSection(getContext().getCOFFSection(
277  SectionName, Flags, Kind, "", (COFF::COMDATType)(0)));
278  return false;
279 }
280 
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();
288 
289  // Ignore; no action necessary.
290  Lex();
291  return false;
292 }
293 
294 /// ParseDirectiveIncludelib
295 /// ::= "includelib" identifier
296 bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
297  StringRef Lib;
298  if (getParser().parseIdentifier(Lib))
299  return TokError("expected identifier in includelib directive");
300 
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();
310  return false;
311 }
312 
313 /// ParseDirectiveProc
314 /// TODO(epastor): Implement parameters and other attributes.
315 /// ::= label "proc" [[distance]]
316 /// statements
317 /// label "endproc"
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.
327  Lex();
328  return Error(nextLoc, "far procedure definitions not yet supported");
329  } else if (nextVal.equals_insensitive("near")) {
330  Lex();
331  nextVal = getTok().getString();
332  nextLoc = getTok().getLoc();
333  }
334  }
335  MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
336 
337  // Define symbol as simple external function
338  Sym->setExternal(true);
340 
341  bool Framed = false;
342  if (getLexer().is(AsmToken::Identifier) &&
343  getTok().getString().equals_insensitive("frame")) {
344  Lex();
345  Framed = true;
346  getStreamer().EmitWinCFIStartProc(Sym, Loc);
347  }
348  getStreamer().emitLabel(Sym, Loc);
349 
350  CurrentProcedure = Label;
351  CurrentProcedureFramed = Framed;
352  return false;
353 }
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");
359 
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 + "'");
365 
366  if (CurrentProcedureFramed) {
367  getStreamer().EmitWinCFIEndProc(Loc);
368  }
369  CurrentProcedure = "";
370  CurrentProcedureFramed = false;
371  return false;
372 }
373 
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>");
384 
385  MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
386  MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
387 
388  getStreamer().emitWeakReference(Alias, Actual);
389 
390  return false;
391 }
392 
393 bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
394  SMLoc Loc) {
395  int64_t Size;
396  SMLoc SizeLoc = getTok().getLoc();
397  if (getParser().parseAbsoluteExpression(Size))
398  return Error(SizeLoc, "expected integer size");
399  if (Size % 8 != 0)
400  return Error(SizeLoc, "stack size must be a multiple of 8");
401  getStreamer().EmitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
402  return false;
403 }
404 
405 bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
406  SMLoc Loc) {
407  getStreamer().EmitWinCFIEndProlog(Loc);
408  return false;
409 }
410 
411 namespace llvm {
412 
413 MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
414 
415 } // end namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
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
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
@ IMAGE_SCN_CNT_UNINITIALIZED_DATA
Definition: COFF.h:290
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
MCDirectives.h
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
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:265
COFF.h
MCObjectFileInfo.h
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
MCAsmParserUtils.h
MCTargetAsmParser.h
llvm::COFF::COMDATType
COMDATType
Definition: COFF.h:406
llvm::ARMBuildAttrs::Section
@ Section
Legacy Tags.
Definition: ARMBuildAttributes.h:78
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:185
llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
@ IMAGE_SCN_CNT_INITIALIZED_DATA
Definition: COFF.h:289
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:321
llvm::SectionKind::getBSS
static SectionKind getBSS()
Definition: SectionKind.h:202
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:177
llvm::MCSymbolCOFF
Definition: MCSymbolCOFF.h:17
SMLoc.h
llvm::SectionKind::getText
static SectionKind getText()
Definition: SectionKind.h:183
isNot
static bool isNot(const MachineRegisterInfo &MRI, const MachineInstr &MI)
Definition: AMDGPULegalizerInfo.cpp:2749
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:19
MCRegisterInfo.h
llvm::AsmToken::Less
@ Less
Definition: MCAsmMacro.h:53
Triple.h
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:25
llvm::SectionKind::getData
static SectionKind getData()
Definition: SectionKind.h:206
llvm::MCSymbol::setExternal
void setExternal(bool Value) const
Definition: MCSymbol.h:399
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:299
llvm::SectionName
Definition: DWARFSection.h:21
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::COFF::IMAGE_SCN_CNT_CODE
@ IMAGE_SCN_CNT_CODE
Definition: COFF.h:288
MCSymbolCOFF.h
SectionKind.h
computeSectionKind
static SectionKind computeSectionKind(unsigned Flags)
Definition: COFFMasmParser.cpp:223
MCStreamer.h
Characteristics
COFFYAML::WeakExternalCharacteristics Characteristics
Definition: COFFYAML.cpp:326
llvm::COFF::IMAGE_SCN_MEM_EXECUTE
@ IMAGE_SCN_MEM_EXECUTE
Definition: COFF.h:320
llvm::COFF::IMAGE_SCN_MEM_16BIT
@ IMAGE_SCN_MEM_16BIT
Definition: COFF.h:297
llvm::StringRef::size
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:157
llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
Definition: COFF.h:261
llvm::Directive
Definition: DirectiveEmitter.h:100
llvm::COFF::IMAGE_SCN_MEM_WRITE
@ IMAGE_SCN_MEM_WRITE
Definition: COFF.h:322
llvm::createCOFFMasmParser
MCAsmParserExtension * createCOFFMasmParser()
Definition: COFFMasmParser.cpp:413