Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/MC/MCParser/COFFMasmParser.cpp
35294 views
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/MCAsmMacro.h"
13
#include "llvm/MC/MCContext.h"
14
#include "llvm/MC/MCParser/MCAsmLexer.h"
15
#include "llvm/MC/MCParser/MCAsmParserExtension.h"
16
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
17
#include "llvm/MC/MCSectionCOFF.h"
18
#include "llvm/MC/MCStreamer.h"
19
#include "llvm/MC/MCSymbolCOFF.h"
20
#include "llvm/MC/SectionKind.h"
21
#include "llvm/Support/Casting.h"
22
#include "llvm/Support/SMLoc.h"
23
#include <cstdint>
24
#include <utility>
25
26
using namespace llvm;
27
28
namespace {
29
30
class COFFMasmParser : public MCAsmParserExtension {
31
template <bool (COFFMasmParser::*HandlerMethod)(StringRef, SMLoc)>
32
void addDirectiveHandler(StringRef Directive) {
33
MCAsmParser::ExtensionDirectiveHandler Handler =
34
std::make_pair(this, HandleDirective<COFFMasmParser, HandlerMethod>);
35
getParser().addDirectiveHandler(Directive, Handler);
36
}
37
38
bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics);
39
40
bool ParseSectionSwitch(StringRef SectionName, unsigned Characteristics,
41
StringRef COMDATSymName, COFF::COMDATType Type,
42
Align Alignment);
43
44
bool ParseDirectiveProc(StringRef, SMLoc);
45
bool ParseDirectiveEndProc(StringRef, SMLoc);
46
bool ParseDirectiveSegment(StringRef, SMLoc);
47
bool ParseDirectiveSegmentEnd(StringRef, SMLoc);
48
bool ParseDirectiveIncludelib(StringRef, SMLoc);
49
bool ParseDirectiveOption(StringRef, SMLoc);
50
51
bool ParseDirectiveAlias(StringRef, SMLoc);
52
53
bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
54
bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
55
56
bool IgnoreDirective(StringRef, SMLoc) {
57
while (!getLexer().is(AsmToken::EndOfStatement)) {
58
Lex();
59
}
60
return false;
61
}
62
63
void Initialize(MCAsmParser &Parser) override {
64
// Call the base implementation.
65
MCAsmParserExtension::Initialize(Parser);
66
67
// x64 directives
68
addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveAllocStack>(
69
".allocstack");
70
addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>(
71
".endprolog");
72
73
// Code label directives
74
// label
75
// org
76
77
// Conditional control flow directives
78
// .break
79
// .continue
80
// .else
81
// .elseif
82
// .endif
83
// .endw
84
// .if
85
// .repeat
86
// .until
87
// .untilcxz
88
// .while
89
90
// Data allocation directives
91
// align
92
// even
93
// mmword
94
// tbyte
95
// xmmword
96
// ymmword
97
98
// Listing control directives
99
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".cref");
100
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".list");
101
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listall");
102
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listif");
103
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacro");
104
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".listmacroall");
105
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nocref");
106
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolist");
107
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistif");
108
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".nolistmacro");
109
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("page");
110
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("subtitle");
111
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".tfcond");
112
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>("title");
113
114
// Macro directives
115
// goto
116
117
// Miscellaneous directives
118
addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>("alias");
119
// assume
120
// .fpo
121
addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>(
122
"includelib");
123
addDirectiveHandler<&COFFMasmParser::ParseDirectiveOption>("option");
124
// popcontext
125
// pushcontext
126
// .safeseh
127
128
// Procedure directives
129
addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>("endp");
130
// invoke (32-bit only)
131
addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>("proc");
132
// proto
133
134
// Processor directives; all ignored
135
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386");
136
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".386p");
137
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".387");
138
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486");
139
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".486p");
140
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586");
141
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".586p");
142
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686");
143
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".686p");
144
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".k3d");
145
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".mmx");
146
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".xmm");
147
148
// Scope directives
149
// comm
150
// externdef
151
152
// Segment directives
153
// .alpha (32-bit only, order segments alphabetically)
154
// .dosseg (32-bit only, order segments in DOS convention)
155
// .seq (32-bit only, order segments sequentially)
156
addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegmentEnd>("ends");
157
// group (32-bit only)
158
addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>("segment");
159
160
// Simplified segment directives
161
addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(".code");
162
// .const
163
addDirectiveHandler<
164
&COFFMasmParser::ParseSectionDirectiveInitializedData>(".data");
165
addDirectiveHandler<
166
&COFFMasmParser::ParseSectionDirectiveUninitializedData>(".data?");
167
// .exit
168
// .fardata
169
// .fardata?
170
addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(".model");
171
// .stack
172
// .startup
173
174
// String directives, written <name> <directive> <params>
175
// catstr (equivalent to <name> TEXTEQU <params>)
176
// instr (equivalent to <name> = @InStr(<params>))
177
// sizestr (equivalent to <name> = @SizeStr(<params>))
178
// substr (equivalent to <name> TEXTEQU @SubStr(<params>))
179
180
// Structure and record directives
181
// record
182
// typedef
183
}
184
185
bool ParseSectionDirectiveCode(StringRef, SMLoc) {
186
return ParseSectionSwitch(".text", COFF::IMAGE_SCN_CNT_CODE |
187
COFF::IMAGE_SCN_MEM_EXECUTE |
188
COFF::IMAGE_SCN_MEM_READ);
189
}
190
191
bool ParseSectionDirectiveInitializedData(StringRef, SMLoc) {
192
return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
193
COFF::IMAGE_SCN_MEM_READ |
194
COFF::IMAGE_SCN_MEM_WRITE);
195
}
196
197
bool ParseSectionDirectiveUninitializedData(StringRef, SMLoc) {
198
return ParseSectionSwitch(".bss", COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
199
COFF::IMAGE_SCN_MEM_READ |
200
COFF::IMAGE_SCN_MEM_WRITE);
201
}
202
203
/// Stack of active procedure definitions.
204
SmallVector<StringRef, 1> CurrentProcedures;
205
SmallVector<bool, 1> CurrentProceduresFramed;
206
207
public:
208
COFFMasmParser() = default;
209
};
210
211
} // end anonymous namespace.
212
213
bool COFFMasmParser::ParseSectionSwitch(StringRef SectionName,
214
unsigned Characteristics) {
215
return ParseSectionSwitch(SectionName, Characteristics, "",
216
(COFF::COMDATType)0, Align(16));
217
}
218
219
bool COFFMasmParser::ParseSectionSwitch(StringRef SectionName,
220
unsigned Characteristics,
221
StringRef COMDATSymName,
222
COFF::COMDATType Type,
223
Align Alignment) {
224
if (getLexer().isNot(AsmToken::EndOfStatement))
225
return TokError("unexpected token in section switching directive");
226
Lex();
227
228
MCSection *Section = getContext().getCOFFSection(SectionName, Characteristics,
229
COMDATSymName, Type);
230
Section->setAlignment(Alignment);
231
getStreamer().switchSection(Section);
232
233
return false;
234
}
235
236
bool COFFMasmParser::ParseDirectiveSegment(StringRef Directive, SMLoc Loc) {
237
StringRef SegmentName;
238
if (!getLexer().is(AsmToken::Identifier))
239
return TokError("expected identifier in directive");
240
SegmentName = getTok().getIdentifier();
241
Lex();
242
243
StringRef SectionName = SegmentName;
244
SmallVector<char, 247> SectionNameVector;
245
246
StringRef Class;
247
if (SegmentName == "_TEXT" || SegmentName.starts_with("_TEXT$")) {
248
if (SegmentName.size() == 5) {
249
SectionName = ".text";
250
} else {
251
SectionName =
252
(".text$" + SegmentName.substr(6)).toStringRef(SectionNameVector);
253
}
254
Class = "CODE";
255
}
256
257
// Parse all options to end of statement.
258
// Alignment defaults to PARA if unspecified.
259
int64_t Alignment = 16;
260
// Default flags are used only if no characteristics are set.
261
bool DefaultCharacteristics = true;
262
unsigned Flags = 0;
263
// "obsolete" according to the documentation, but still supported.
264
bool Readonly = false;
265
while (getLexer().isNot(AsmToken::EndOfStatement)) {
266
switch (getTok().getKind()) {
267
default:
268
break;
269
case AsmToken::String: {
270
// Class identifier; overrides Kind.
271
Class = getTok().getStringContents();
272
Lex();
273
break;
274
}
275
case AsmToken::Identifier: {
276
SMLoc KeywordLoc = getTok().getLoc();
277
StringRef Keyword;
278
if (getParser().parseIdentifier(Keyword)) {
279
llvm_unreachable("failed to parse identifier at an identifier token");
280
}
281
if (Keyword.equals_insensitive("byte")) {
282
Alignment = 1;
283
} else if (Keyword.equals_insensitive("word")) {
284
Alignment = 2;
285
} else if (Keyword.equals_insensitive("dword")) {
286
Alignment = 4;
287
} else if (Keyword.equals_insensitive("para")) {
288
Alignment = 16;
289
} else if (Keyword.equals_insensitive("page")) {
290
Alignment = 256;
291
} else if (Keyword.equals_insensitive("align")) {
292
if (getParser().parseToken(AsmToken::LParen) ||
293
getParser().parseIntToken(Alignment,
294
"Expected integer alignment") ||
295
getParser().parseToken(AsmToken::RParen)) {
296
return Error(getTok().getLoc(),
297
"Expected (n) following ALIGN in SEGMENT directive");
298
}
299
if (!isPowerOf2_64(Alignment) || Alignment > 8192) {
300
return Error(KeywordLoc,
301
"ALIGN argument must be a power of 2 from 1 to 8192");
302
}
303
} else if (Keyword.equals_insensitive("alias")) {
304
if (getParser().parseToken(AsmToken::LParen) ||
305
!getTok().is(AsmToken::String))
306
return Error(
307
getTok().getLoc(),
308
"Expected (string) following ALIAS in SEGMENT directive");
309
SectionName = getTok().getStringContents();
310
Lex();
311
if (getParser().parseToken(AsmToken::RParen))
312
return Error(
313
getTok().getLoc(),
314
"Expected (string) following ALIAS in SEGMENT directive");
315
} else if (Keyword.equals_insensitive("readonly")) {
316
Readonly = true;
317
} else {
318
unsigned Characteristic =
319
StringSwitch<unsigned>(Keyword)
320
.CaseLower("info", COFF::IMAGE_SCN_LNK_INFO)
321
.CaseLower("read", COFF::IMAGE_SCN_MEM_READ)
322
.CaseLower("write", COFF::IMAGE_SCN_MEM_WRITE)
323
.CaseLower("execute", COFF::IMAGE_SCN_MEM_EXECUTE)
324
.CaseLower("shared", COFF::IMAGE_SCN_MEM_SHARED)
325
.CaseLower("nopage", COFF::IMAGE_SCN_MEM_NOT_PAGED)
326
.CaseLower("nocache", COFF::IMAGE_SCN_MEM_NOT_CACHED)
327
.CaseLower("discard", COFF::IMAGE_SCN_MEM_DISCARDABLE)
328
.Default(-1);
329
if (Characteristic == static_cast<unsigned>(-1)) {
330
return Error(KeywordLoc,
331
"Expected characteristic in SEGMENT directive; found '" +
332
Keyword + "'");
333
}
334
Flags |= Characteristic;
335
DefaultCharacteristics = false;
336
}
337
}
338
}
339
}
340
341
SectionKind Kind = StringSwitch<SectionKind>(Class)
342
.CaseLower("data", SectionKind::getData())
343
.CaseLower("code", SectionKind::getText())
344
.CaseLower("const", SectionKind::getReadOnly())
345
.Default(SectionKind::getData());
346
if (Kind.isText()) {
347
if (DefaultCharacteristics) {
348
Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | COFF::IMAGE_SCN_MEM_READ;
349
}
350
Flags |= COFF::IMAGE_SCN_CNT_CODE;
351
} else {
352
if (DefaultCharacteristics) {
353
Flags |= COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE;
354
}
355
Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
356
}
357
if (Readonly) {
358
Flags &= ~COFF::IMAGE_SCN_MEM_WRITE;
359
}
360
361
MCSection *Section = getContext().getCOFFSection(SectionName, Flags, "",
362
(COFF::COMDATType)(0));
363
if (Alignment != 0) {
364
Section->setAlignment(Align(Alignment));
365
}
366
getStreamer().switchSection(Section);
367
return false;
368
}
369
370
/// ParseDirectiveSegmentEnd
371
/// ::= identifier "ends"
372
bool COFFMasmParser::ParseDirectiveSegmentEnd(StringRef Directive, SMLoc Loc) {
373
StringRef SegmentName;
374
if (!getLexer().is(AsmToken::Identifier))
375
return TokError("expected identifier in directive");
376
SegmentName = getTok().getIdentifier();
377
378
// Ignore; no action necessary.
379
Lex();
380
return false;
381
}
382
383
/// ParseDirectiveIncludelib
384
/// ::= "includelib" identifier
385
bool COFFMasmParser::ParseDirectiveIncludelib(StringRef Directive, SMLoc Loc) {
386
StringRef Lib;
387
if (getParser().parseIdentifier(Lib))
388
return TokError("expected identifier in includelib directive");
389
390
unsigned Flags = COFF::IMAGE_SCN_MEM_PRELOAD | COFF::IMAGE_SCN_MEM_16BIT;
391
getStreamer().pushSection();
392
getStreamer().switchSection(getContext().getCOFFSection(
393
".drectve", Flags, "", (COFF::COMDATType)(0)));
394
getStreamer().emitBytes("/DEFAULTLIB:");
395
getStreamer().emitBytes(Lib);
396
getStreamer().emitBytes(" ");
397
getStreamer().popSection();
398
return false;
399
}
400
401
/// ParseDirectiveOption
402
/// ::= "option" option-list
403
bool COFFMasmParser::ParseDirectiveOption(StringRef Directive, SMLoc Loc) {
404
auto parseOption = [&]() -> bool {
405
StringRef Option;
406
if (getParser().parseIdentifier(Option))
407
return TokError("expected identifier for option name");
408
if (Option.equals_insensitive("prologue")) {
409
StringRef MacroId;
410
if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
411
return TokError("expected :macroId after OPTION PROLOGUE");
412
if (MacroId.equals_insensitive("none")) {
413
// Since we currently don't implement prologues/epilogues, NONE is our
414
// default.
415
return false;
416
}
417
return TokError("OPTION PROLOGUE is currently unsupported");
418
}
419
if (Option.equals_insensitive("epilogue")) {
420
StringRef MacroId;
421
if (parseToken(AsmToken::Colon) || getParser().parseIdentifier(MacroId))
422
return TokError("expected :macroId after OPTION EPILOGUE");
423
if (MacroId.equals_insensitive("none")) {
424
// Since we currently don't implement prologues/epilogues, NONE is our
425
// default.
426
return false;
427
}
428
return TokError("OPTION EPILOGUE is currently unsupported");
429
}
430
return TokError("OPTION '" + Option + "' is currently unsupported");
431
};
432
433
if (parseMany(parseOption))
434
return addErrorSuffix(" in OPTION directive");
435
return false;
436
}
437
438
/// ParseDirectiveProc
439
/// TODO(epastor): Implement parameters and other attributes.
440
/// ::= label "proc" [[distance]]
441
/// statements
442
/// label "endproc"
443
bool COFFMasmParser::ParseDirectiveProc(StringRef Directive, SMLoc Loc) {
444
StringRef Label;
445
if (getParser().parseIdentifier(Label))
446
return Error(Loc, "expected identifier for procedure");
447
if (getLexer().is(AsmToken::Identifier)) {
448
StringRef nextVal = getTok().getString();
449
SMLoc nextLoc = getTok().getLoc();
450
if (nextVal.equals_insensitive("far")) {
451
// TODO(epastor): Handle far procedure definitions.
452
Lex();
453
return Error(nextLoc, "far procedure definitions not yet supported");
454
} else if (nextVal.equals_insensitive("near")) {
455
Lex();
456
nextVal = getTok().getString();
457
nextLoc = getTok().getLoc();
458
}
459
}
460
MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(getContext().getOrCreateSymbol(Label));
461
462
// Define symbol as simple external function
463
Sym->setExternal(true);
464
Sym->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT);
465
466
bool Framed = false;
467
if (getLexer().is(AsmToken::Identifier) &&
468
getTok().getString().equals_insensitive("frame")) {
469
Lex();
470
Framed = true;
471
getStreamer().emitWinCFIStartProc(Sym, Loc);
472
}
473
getStreamer().emitLabel(Sym, Loc);
474
475
CurrentProcedures.push_back(Label);
476
CurrentProceduresFramed.push_back(Framed);
477
return false;
478
}
479
bool COFFMasmParser::ParseDirectiveEndProc(StringRef Directive, SMLoc Loc) {
480
StringRef Label;
481
SMLoc LabelLoc = getTok().getLoc();
482
if (getParser().parseIdentifier(Label))
483
return Error(LabelLoc, "expected identifier for procedure end");
484
485
if (CurrentProcedures.empty())
486
return Error(Loc, "endp outside of procedure block");
487
else if (!CurrentProcedures.back().equals_insensitive(Label))
488
return Error(LabelLoc, "endp does not match current procedure '" +
489
CurrentProcedures.back() + "'");
490
491
if (CurrentProceduresFramed.back()) {
492
getStreamer().emitWinCFIEndProc(Loc);
493
}
494
CurrentProcedures.pop_back();
495
CurrentProceduresFramed.pop_back();
496
return false;
497
}
498
499
bool COFFMasmParser::ParseDirectiveAlias(StringRef Directive, SMLoc Loc) {
500
std::string AliasName, ActualName;
501
if (getTok().isNot(AsmToken::Less) ||
502
getParser().parseAngleBracketString(AliasName))
503
return Error(getTok().getLoc(), "expected <aliasName>");
504
if (getParser().parseToken(AsmToken::Equal))
505
return addErrorSuffix(" in " + Directive + " directive");
506
if (getTok().isNot(AsmToken::Less) ||
507
getParser().parseAngleBracketString(ActualName))
508
return Error(getTok().getLoc(), "expected <actualName>");
509
510
MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
511
MCSymbol *Actual = getContext().getOrCreateSymbol(ActualName);
512
513
getStreamer().emitWeakReference(Alias, Actual);
514
515
return false;
516
}
517
518
bool COFFMasmParser::ParseSEHDirectiveAllocStack(StringRef Directive,
519
SMLoc Loc) {
520
int64_t Size;
521
SMLoc SizeLoc = getTok().getLoc();
522
if (getParser().parseAbsoluteExpression(Size))
523
return Error(SizeLoc, "expected integer size");
524
if (Size % 8 != 0)
525
return Error(SizeLoc, "stack size must be a multiple of 8");
526
getStreamer().emitWinCFIAllocStack(static_cast<unsigned>(Size), Loc);
527
return false;
528
}
529
530
bool COFFMasmParser::ParseSEHDirectiveEndProlog(StringRef Directive,
531
SMLoc Loc) {
532
getStreamer().emitWinCFIEndProlog(Loc);
533
return false;
534
}
535
536
namespace llvm {
537
538
MCAsmParserExtension *createCOFFMasmParser() { return new COFFMasmParser; }
539
540
} // end namespace llvm
541
542