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