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(K: 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 | Directive: ".allocstack" ); |
70 | addDirectiveHandler<&COFFMasmParser::ParseSEHDirectiveEndProlog>( |
71 | Directive: ".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>(Directive: ".cref" ); |
100 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".list" ); |
101 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listall" ); |
102 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listif" ); |
103 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listmacro" ); |
104 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".listmacroall" ); |
105 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nocref" ); |
106 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolist" ); |
107 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolistif" ); |
108 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".nolistmacro" ); |
109 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "page" ); |
110 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "subtitle" ); |
111 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".tfcond" ); |
112 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: "title" ); |
113 | |
114 | // Macro directives |
115 | // goto |
116 | |
117 | // Miscellaneous directives |
118 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveAlias>(Directive: "alias" ); |
119 | // assume |
120 | // .fpo |
121 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveIncludelib>( |
122 | Directive: "includelib" ); |
123 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveOption>(Directive: "option" ); |
124 | // popcontext |
125 | // pushcontext |
126 | // .safeseh |
127 | |
128 | // Procedure directives |
129 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveEndProc>(Directive: "endp" ); |
130 | // invoke (32-bit only) |
131 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveProc>(Directive: "proc" ); |
132 | // proto |
133 | |
134 | // Processor directives; all ignored |
135 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".386" ); |
136 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".386p" ); |
137 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".387" ); |
138 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".486" ); |
139 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".486p" ); |
140 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".586" ); |
141 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".586p" ); |
142 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".686" ); |
143 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".686p" ); |
144 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".k3d" ); |
145 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".mmx" ); |
146 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".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>(Directive: "ends" ); |
157 | // group (32-bit only) |
158 | addDirectiveHandler<&COFFMasmParser::ParseDirectiveSegment>(Directive: "segment" ); |
159 | |
160 | // Simplified segment directives |
161 | addDirectiveHandler<&COFFMasmParser::ParseSectionDirectiveCode>(Directive: ".code" ); |
162 | // .const |
163 | addDirectiveHandler< |
164 | &COFFMasmParser::ParseSectionDirectiveInitializedData>(Directive: ".data" ); |
165 | addDirectiveHandler< |
166 | &COFFMasmParser::ParseSectionDirectiveUninitializedData>(Directive: ".data?" ); |
167 | // .exit |
168 | // .fardata |
169 | // .fardata? |
170 | addDirectiveHandler<&COFFMasmParser::IgnoreDirective>(Directive: ".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(SectionName: ".text" , Characteristics: 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(SectionName: ".data" , Characteristics: 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(SectionName: ".bss" , Characteristics: 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, COMDATSymName: "" , |
216 | Type: (COFF::COMDATType)0, Alignment: 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(K: AsmToken::EndOfStatement)) |
225 | return TokError(Msg: "unexpected token in section switching directive" ); |
226 | Lex(); |
227 | |
228 | MCSection *Section = getContext().getCOFFSection(Section: SectionName, Characteristics, |
229 | COMDATSymName, Selection: 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(K: AsmToken::Identifier)) |
239 | return TokError(Msg: "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(Prefix: "_TEXT$" )) { |
248 | if (SegmentName.size() == 5) { |
249 | SectionName = ".text" ; |
250 | } else { |
251 | SectionName = |
252 | (".text$" + SegmentName.substr(Start: 6)).toStringRef(Out&: 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(K: 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(Res&: Keyword)) { |
279 | llvm_unreachable("failed to parse identifier at an identifier token" ); |
280 | } |
281 | if (Keyword.equals_insensitive(RHS: "byte" )) { |
282 | Alignment = 1; |
283 | } else if (Keyword.equals_insensitive(RHS: "word" )) { |
284 | Alignment = 2; |
285 | } else if (Keyword.equals_insensitive(RHS: "dword" )) { |
286 | Alignment = 4; |
287 | } else if (Keyword.equals_insensitive(RHS: "para" )) { |
288 | Alignment = 16; |
289 | } else if (Keyword.equals_insensitive(RHS: "page" )) { |
290 | Alignment = 256; |
291 | } else if (Keyword.equals_insensitive(RHS: "align" )) { |
292 | if (getParser().parseToken(T: AsmToken::LParen) || |
293 | getParser().parseIntToken(V&: Alignment, |
294 | ErrMsg: "Expected integer alignment" ) || |
295 | getParser().parseToken(T: AsmToken::RParen)) { |
296 | return Error(L: getTok().getLoc(), |
297 | Msg: "Expected (n) following ALIGN in SEGMENT directive" ); |
298 | } |
299 | if (!isPowerOf2_64(Value: Alignment) || Alignment > 8192) { |
300 | return Error(L: KeywordLoc, |
301 | Msg: "ALIGN argument must be a power of 2 from 1 to 8192" ); |
302 | } |
303 | } else if (Keyword.equals_insensitive(RHS: "alias" )) { |
304 | if (getParser().parseToken(T: AsmToken::LParen) || |
305 | !getTok().is(K: AsmToken::String)) |
306 | return Error( |
307 | L: getTok().getLoc(), |
308 | Msg: "Expected (string) following ALIAS in SEGMENT directive" ); |
309 | SectionName = getTok().getStringContents(); |
310 | Lex(); |
311 | if (getParser().parseToken(T: AsmToken::RParen)) |
312 | return Error( |
313 | L: getTok().getLoc(), |
314 | Msg: "Expected (string) following ALIAS in SEGMENT directive" ); |
315 | } else if (Keyword.equals_insensitive(RHS: "readonly" )) { |
316 | Readonly = true; |
317 | } else { |
318 | unsigned Characteristic = |
319 | StringSwitch<unsigned>(Keyword) |
320 | .CaseLower(S: "info" , Value: COFF::IMAGE_SCN_LNK_INFO) |
321 | .CaseLower(S: "read" , Value: COFF::IMAGE_SCN_MEM_READ) |
322 | .CaseLower(S: "write" , Value: COFF::IMAGE_SCN_MEM_WRITE) |
323 | .CaseLower(S: "execute" , Value: COFF::IMAGE_SCN_MEM_EXECUTE) |
324 | .CaseLower(S: "shared" , Value: COFF::IMAGE_SCN_MEM_SHARED) |
325 | .CaseLower(S: "nopage" , Value: COFF::IMAGE_SCN_MEM_NOT_PAGED) |
326 | .CaseLower(S: "nocache" , Value: COFF::IMAGE_SCN_MEM_NOT_CACHED) |
327 | .CaseLower(S: "discard" , Value: COFF::IMAGE_SCN_MEM_DISCARDABLE) |
328 | .Default(Value: -1); |
329 | if (Characteristic == static_cast<unsigned>(-1)) { |
330 | return Error(L: KeywordLoc, |
331 | Msg: "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(S: "data" , Value: SectionKind::getData()) |
343 | .CaseLower(S: "code" , Value: SectionKind::getText()) |
344 | .CaseLower(S: "const" , Value: SectionKind::getReadOnly()) |
345 | .Default(Value: 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(Section: SectionName, Characteristics: Flags, COMDATSymName: "" , |
362 | Selection: (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(K: AsmToken::Identifier)) |
375 | return TokError(Msg: "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(Res&: Lib)) |
388 | return TokError(Msg: "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(Section: getContext().getCOFFSection( |
393 | Section: ".drectve" , Characteristics: Flags, COMDATSymName: "" , Selection: (COFF::COMDATType)(0))); |
394 | getStreamer().emitBytes(Data: "/DEFAULTLIB:" ); |
395 | getStreamer().emitBytes(Data: Lib); |
396 | getStreamer().emitBytes(Data: " " ); |
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(Res&: Option)) |
407 | return TokError(Msg: "expected identifier for option name" ); |
408 | if (Option.equals_insensitive(RHS: "prologue" )) { |
409 | StringRef MacroId; |
410 | if (parseToken(T: AsmToken::Colon) || getParser().parseIdentifier(Res&: MacroId)) |
411 | return TokError(Msg: "expected :macroId after OPTION PROLOGUE" ); |
412 | if (MacroId.equals_insensitive(RHS: "none" )) { |
413 | // Since we currently don't implement prologues/epilogues, NONE is our |
414 | // default. |
415 | return false; |
416 | } |
417 | return TokError(Msg: "OPTION PROLOGUE is currently unsupported" ); |
418 | } |
419 | if (Option.equals_insensitive(RHS: "epilogue" )) { |
420 | StringRef MacroId; |
421 | if (parseToken(T: AsmToken::Colon) || getParser().parseIdentifier(Res&: MacroId)) |
422 | return TokError(Msg: "expected :macroId after OPTION EPILOGUE" ); |
423 | if (MacroId.equals_insensitive(RHS: "none" )) { |
424 | // Since we currently don't implement prologues/epilogues, NONE is our |
425 | // default. |
426 | return false; |
427 | } |
428 | return TokError(Msg: "OPTION EPILOGUE is currently unsupported" ); |
429 | } |
430 | return TokError(Msg: "OPTION '" + Option + "' is currently unsupported" ); |
431 | }; |
432 | |
433 | if (parseMany(parseOne: parseOption)) |
434 | return addErrorSuffix(Suffix: " 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(Res&: Label)) |
446 | return Error(L: Loc, Msg: "expected identifier for procedure" ); |
447 | if (getLexer().is(K: AsmToken::Identifier)) { |
448 | StringRef nextVal = getTok().getString(); |
449 | SMLoc nextLoc = getTok().getLoc(); |
450 | if (nextVal.equals_insensitive(RHS: "far" )) { |
451 | // TODO(epastor): Handle far procedure definitions. |
452 | Lex(); |
453 | return Error(L: nextLoc, Msg: "far procedure definitions not yet supported" ); |
454 | } else if (nextVal.equals_insensitive(RHS: "near" )) { |
455 | Lex(); |
456 | nextVal = getTok().getString(); |
457 | nextLoc = getTok().getLoc(); |
458 | } |
459 | } |
460 | MCSymbolCOFF *Sym = cast<MCSymbolCOFF>(Val: getContext().getOrCreateSymbol(Name: 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(K: AsmToken::Identifier) && |
468 | getTok().getString().equals_insensitive(RHS: "frame" )) { |
469 | Lex(); |
470 | Framed = true; |
471 | getStreamer().emitWinCFIStartProc(Symbol: Sym, Loc); |
472 | } |
473 | getStreamer().emitLabel(Symbol: Sym, Loc); |
474 | |
475 | CurrentProcedures.push_back(Elt: Label); |
476 | CurrentProceduresFramed.push_back(Elt: 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(Res&: Label)) |
483 | return Error(L: LabelLoc, Msg: "expected identifier for procedure end" ); |
484 | |
485 | if (CurrentProcedures.empty()) |
486 | return Error(L: Loc, Msg: "endp outside of procedure block" ); |
487 | else if (!CurrentProcedures.back().equals_insensitive(RHS: Label)) |
488 | return Error(L: LabelLoc, Msg: "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(K: AsmToken::Less) || |
502 | getParser().parseAngleBracketString(Data&: AliasName)) |
503 | return Error(L: getTok().getLoc(), Msg: "expected <aliasName>" ); |
504 | if (getParser().parseToken(T: AsmToken::Equal)) |
505 | return addErrorSuffix(Suffix: " in " + Directive + " directive" ); |
506 | if (getTok().isNot(K: AsmToken::Less) || |
507 | getParser().parseAngleBracketString(Data&: ActualName)) |
508 | return Error(L: getTok().getLoc(), Msg: "expected <actualName>" ); |
509 | |
510 | MCSymbol *Alias = getContext().getOrCreateSymbol(Name: AliasName); |
511 | MCSymbol *Actual = getContext().getOrCreateSymbol(Name: ActualName); |
512 | |
513 | getStreamer().emitWeakReference(Alias, Symbol: 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(Res&: Size)) |
523 | return Error(L: SizeLoc, Msg: "expected integer size" ); |
524 | if (Size % 8 != 0) |
525 | return Error(L: SizeLoc, Msg: "stack size must be a multiple of 8" ); |
526 | getStreamer().emitWinCFIAllocStack(Size: 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 | |