1 | //===- COFFAsmParser.cpp - COFF 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/StringSwitch.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" |
15 | #include "llvm/MC/MCParser/AsmLexer.h" |
16 | #include "llvm/MC/MCParser/MCAsmParserExtension.h" |
17 | #include "llvm/MC/MCSectionCOFF.h" |
18 | #include "llvm/MC/MCStreamer.h" |
19 | #include "llvm/Support/SMLoc.h" |
20 | #include "llvm/TargetParser/Triple.h" |
21 | #include <cassert> |
22 | #include <cstdint> |
23 | #include <limits> |
24 | #include <utility> |
25 | |
26 | using namespace llvm; |
27 | |
28 | namespace { |
29 | |
30 | class COFFAsmParser : public MCAsmParserExtension { |
31 | template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)> |
32 | void addDirectiveHandler(StringRef Directive) { |
33 | MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( |
34 | this, HandleDirective<COFFAsmParser, HandlerMethod>); |
35 | getParser().addDirectiveHandler(Directive, Handler); |
36 | } |
37 | |
38 | bool parseSectionSwitch(StringRef Section, unsigned Characteristics); |
39 | |
40 | bool parseSectionSwitch(StringRef Section, unsigned Characteristics, |
41 | StringRef COMDATSymName, COFF::COMDATType Type, |
42 | unsigned UniqueID); |
43 | |
44 | bool parseSectionName(StringRef &SectionName); |
45 | bool parseSectionFlags(StringRef SectionName, StringRef FlagsString, |
46 | unsigned *Flags); |
47 | void Initialize(MCAsmParser &Parser) override { |
48 | // Call the base implementation. |
49 | MCAsmParserExtension::Initialize(Parser); |
50 | |
51 | addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveText>(Directive: ".text" ); |
52 | addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveData>(Directive: ".data" ); |
53 | addDirectiveHandler<&COFFAsmParser::parseSectionDirectiveBSS>(Directive: ".bss" ); |
54 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSection>(Directive: ".section" ); |
55 | addDirectiveHandler<&COFFAsmParser::parseDirectivePushSection>( |
56 | Directive: ".pushsection" ); |
57 | addDirectiveHandler<&COFFAsmParser::parseDirectivePopSection>( |
58 | Directive: ".popsection" ); |
59 | addDirectiveHandler<&COFFAsmParser::parseDirectiveDef>(Directive: ".def" ); |
60 | addDirectiveHandler<&COFFAsmParser::parseDirectiveScl>(Directive: ".scl" ); |
61 | addDirectiveHandler<&COFFAsmParser::parseDirectiveType>(Directive: ".type" ); |
62 | addDirectiveHandler<&COFFAsmParser::parseDirectiveEndef>(Directive: ".endef" ); |
63 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSecRel32>(Directive: ".secrel32" ); |
64 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSymIdx>(Directive: ".symidx" ); |
65 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSafeSEH>(Directive: ".safeseh" ); |
66 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSecIdx>(Directive: ".secidx" ); |
67 | addDirectiveHandler<&COFFAsmParser::parseDirectiveLinkOnce>(Directive: ".linkonce" ); |
68 | addDirectiveHandler<&COFFAsmParser::parseDirectiveRVA>(Directive: ".rva" ); |
69 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSymbolAttribute>(Directive: ".weak" ); |
70 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSymbolAttribute>( |
71 | Directive: ".weak_anti_dep" ); |
72 | addDirectiveHandler<&COFFAsmParser::parseDirectiveCGProfile>(Directive: ".cg_profile" ); |
73 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSecNum>(Directive: ".secnum" ); |
74 | addDirectiveHandler<&COFFAsmParser::parseDirectiveSecOffset>(Directive: ".secoffset" ); |
75 | |
76 | // Win64 EH directives. |
77 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartProc>( |
78 | Directive: ".seh_proc" ); |
79 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProc>( |
80 | Directive: ".seh_endproc" ); |
81 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc>( |
82 | Directive: ".seh_endfunclet" ); |
83 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveStartChained>( |
84 | Directive: ".seh_startchained" ); |
85 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndChained>( |
86 | Directive: ".seh_endchained" ); |
87 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandler>( |
88 | Directive: ".seh_handler" ); |
89 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveHandlerData>( |
90 | Directive: ".seh_handlerdata" ); |
91 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveAllocStack>( |
92 | Directive: ".seh_stackalloc" ); |
93 | addDirectiveHandler<&COFFAsmParser::parseSEHDirectiveEndProlog>( |
94 | Directive: ".seh_endprologue" ); |
95 | addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveBeginEpilog>( |
96 | Directive: ".seh_startepilogue" ); |
97 | addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndEpilog>( |
98 | Directive: ".seh_endepilogue" ); |
99 | addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindV2Start>( |
100 | Directive: ".seh_unwindv2start" ); |
101 | addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveUnwindVersion>( |
102 | Directive: ".seh_unwindversion" ); |
103 | } |
104 | |
105 | bool parseSectionDirectiveText(StringRef, SMLoc) { |
106 | return parseSectionSwitch(Section: ".text" , Characteristics: COFF::IMAGE_SCN_CNT_CODE | |
107 | COFF::IMAGE_SCN_MEM_EXECUTE | |
108 | COFF::IMAGE_SCN_MEM_READ); |
109 | } |
110 | |
111 | bool parseSectionDirectiveData(StringRef, SMLoc) { |
112 | return parseSectionSwitch(Section: ".data" , Characteristics: COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | |
113 | COFF::IMAGE_SCN_MEM_READ | |
114 | COFF::IMAGE_SCN_MEM_WRITE); |
115 | } |
116 | |
117 | bool parseSectionDirectiveBSS(StringRef, SMLoc) { |
118 | return parseSectionSwitch(Section: ".bss" , Characteristics: COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | |
119 | COFF::IMAGE_SCN_MEM_READ | |
120 | COFF::IMAGE_SCN_MEM_WRITE); |
121 | } |
122 | |
123 | bool parseDirectiveSection(StringRef, SMLoc); |
124 | bool parseSectionArguments(StringRef, SMLoc); |
125 | bool parseDirectivePushSection(StringRef, SMLoc); |
126 | bool parseDirectivePopSection(StringRef, SMLoc); |
127 | bool parseDirectiveDef(StringRef, SMLoc); |
128 | bool parseDirectiveScl(StringRef, SMLoc); |
129 | bool parseDirectiveType(StringRef, SMLoc); |
130 | bool parseDirectiveEndef(StringRef, SMLoc); |
131 | bool parseDirectiveSecRel32(StringRef, SMLoc); |
132 | bool parseDirectiveSecIdx(StringRef, SMLoc); |
133 | bool parseDirectiveSafeSEH(StringRef, SMLoc); |
134 | bool parseDirectiveSymIdx(StringRef, SMLoc); |
135 | bool parseCOMDATType(COFF::COMDATType &Type); |
136 | bool parseDirectiveLinkOnce(StringRef, SMLoc); |
137 | bool parseDirectiveRVA(StringRef, SMLoc); |
138 | bool parseDirectiveCGProfile(StringRef, SMLoc); |
139 | bool parseDirectiveSecNum(StringRef, SMLoc); |
140 | bool parseDirectiveSecOffset(StringRef, SMLoc); |
141 | |
142 | // Win64 EH directives. |
143 | bool parseSEHDirectiveStartProc(StringRef, SMLoc); |
144 | bool parseSEHDirectiveEndProc(StringRef, SMLoc); |
145 | bool parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc); |
146 | bool parseSEHDirectiveStartChained(StringRef, SMLoc); |
147 | bool parseSEHDirectiveEndChained(StringRef, SMLoc); |
148 | bool parseSEHDirectiveHandler(StringRef, SMLoc); |
149 | bool parseSEHDirectiveHandlerData(StringRef, SMLoc); |
150 | bool parseSEHDirectiveAllocStack(StringRef, SMLoc); |
151 | bool parseSEHDirectiveEndProlog(StringRef, SMLoc); |
152 | bool ParseSEHDirectiveBeginEpilog(StringRef, SMLoc); |
153 | bool ParseSEHDirectiveEndEpilog(StringRef, SMLoc); |
154 | bool ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc); |
155 | bool ParseSEHDirectiveUnwindVersion(StringRef, SMLoc); |
156 | |
157 | bool parseAtUnwindOrAtExcept(bool &unwind, bool &except); |
158 | bool parseDirectiveSymbolAttribute(StringRef Directive, SMLoc); |
159 | |
160 | public: |
161 | COFFAsmParser() = default; |
162 | }; |
163 | |
164 | } // end anonymous namespace. |
165 | |
166 | bool COFFAsmParser::parseSectionFlags(StringRef SectionName, |
167 | StringRef FlagsString, unsigned *Flags) { |
168 | enum { |
169 | None = 0, |
170 | Alloc = 1 << 0, |
171 | Code = 1 << 1, |
172 | Load = 1 << 2, |
173 | InitData = 1 << 3, |
174 | Shared = 1 << 4, |
175 | NoLoad = 1 << 5, |
176 | NoRead = 1 << 6, |
177 | NoWrite = 1 << 7, |
178 | Discardable = 1 << 8, |
179 | Info = 1 << 9, |
180 | }; |
181 | |
182 | bool ReadOnlyRemoved = false; |
183 | unsigned SecFlags = None; |
184 | |
185 | for (char FlagChar : FlagsString) { |
186 | switch (FlagChar) { |
187 | case 'a': |
188 | // Ignored. |
189 | break; |
190 | |
191 | case 'b': // bss section |
192 | SecFlags |= Alloc; |
193 | if (SecFlags & InitData) |
194 | return TokError(Msg: "conflicting section flags 'b' and 'd'." ); |
195 | SecFlags &= ~Load; |
196 | break; |
197 | |
198 | case 'd': // data section |
199 | SecFlags |= InitData; |
200 | if (SecFlags & Alloc) |
201 | return TokError(Msg: "conflicting section flags 'b' and 'd'." ); |
202 | SecFlags &= ~NoWrite; |
203 | if ((SecFlags & NoLoad) == 0) |
204 | SecFlags |= Load; |
205 | break; |
206 | |
207 | case 'n': // section is not loaded |
208 | SecFlags |= NoLoad; |
209 | SecFlags &= ~Load; |
210 | break; |
211 | |
212 | case 'D': // discardable |
213 | SecFlags |= Discardable; |
214 | break; |
215 | |
216 | case 'r': // read-only |
217 | ReadOnlyRemoved = false; |
218 | SecFlags |= NoWrite; |
219 | if ((SecFlags & Code) == 0) |
220 | SecFlags |= InitData; |
221 | if ((SecFlags & NoLoad) == 0) |
222 | SecFlags |= Load; |
223 | break; |
224 | |
225 | case 's': // shared section |
226 | SecFlags |= Shared | InitData; |
227 | SecFlags &= ~NoWrite; |
228 | if ((SecFlags & NoLoad) == 0) |
229 | SecFlags |= Load; |
230 | break; |
231 | |
232 | case 'w': // writable |
233 | SecFlags &= ~NoWrite; |
234 | ReadOnlyRemoved = true; |
235 | break; |
236 | |
237 | case 'x': // executable section |
238 | SecFlags |= Code; |
239 | if ((SecFlags & NoLoad) == 0) |
240 | SecFlags |= Load; |
241 | if (!ReadOnlyRemoved) |
242 | SecFlags |= NoWrite; |
243 | break; |
244 | |
245 | case 'y': // not readable |
246 | SecFlags |= NoRead | NoWrite; |
247 | break; |
248 | |
249 | case 'i': // info |
250 | SecFlags |= Info; |
251 | break; |
252 | |
253 | default: |
254 | return TokError(Msg: "unknown flag" ); |
255 | } |
256 | } |
257 | |
258 | *Flags = 0; |
259 | |
260 | if (SecFlags == None) |
261 | SecFlags = InitData; |
262 | |
263 | if (SecFlags & Code) |
264 | *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; |
265 | if (SecFlags & InitData) |
266 | *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; |
267 | if ((SecFlags & Alloc) && (SecFlags & Load) == 0) |
268 | *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; |
269 | if (SecFlags & NoLoad) |
270 | *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; |
271 | if ((SecFlags & Discardable) || |
272 | MCSectionCOFF::isImplicitlyDiscardable(Name: SectionName)) |
273 | *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE; |
274 | if ((SecFlags & NoRead) == 0) |
275 | *Flags |= COFF::IMAGE_SCN_MEM_READ; |
276 | if ((SecFlags & NoWrite) == 0) |
277 | *Flags |= COFF::IMAGE_SCN_MEM_WRITE; |
278 | if (SecFlags & Shared) |
279 | *Flags |= COFF::IMAGE_SCN_MEM_SHARED; |
280 | if (SecFlags & Info) |
281 | *Flags |= COFF::IMAGE_SCN_LNK_INFO; |
282 | |
283 | return false; |
284 | } |
285 | |
286 | /// ParseDirectiveSymbolAttribute |
287 | /// ::= { ".weak", ... } [ identifier ( , identifier )* ] |
288 | bool COFFAsmParser::parseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { |
289 | MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) |
290 | .Case(S: ".weak" , Value: MCSA_Weak) |
291 | .Case(S: ".weak_anti_dep" , Value: MCSA_WeakAntiDep) |
292 | .Default(Value: MCSA_Invalid); |
293 | assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!" ); |
294 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) { |
295 | while (true) { |
296 | StringRef Name; |
297 | |
298 | if (getParser().parseIdentifier(Res&: Name)) |
299 | return TokError(Msg: "expected identifier in directive" ); |
300 | |
301 | MCSymbol *Sym = getContext().getOrCreateSymbol(Name); |
302 | |
303 | getStreamer().emitSymbolAttribute(Symbol: Sym, Attribute: Attr); |
304 | |
305 | if (getLexer().is(K: AsmToken::EndOfStatement)) |
306 | break; |
307 | |
308 | if (getLexer().isNot(K: AsmToken::Comma)) |
309 | return TokError(Msg: "unexpected token in directive" ); |
310 | Lex(); |
311 | } |
312 | } |
313 | |
314 | Lex(); |
315 | return false; |
316 | } |
317 | |
318 | bool COFFAsmParser::parseDirectiveCGProfile(StringRef S, SMLoc Loc) { |
319 | return MCAsmParserExtension::parseDirectiveCGProfile(S, Loc); |
320 | } |
321 | |
322 | bool COFFAsmParser::parseSectionSwitch(StringRef Section, |
323 | unsigned Characteristics) { |
324 | return parseSectionSwitch(Section, Characteristics, COMDATSymName: "" , Type: (COFF::COMDATType)0, |
325 | UniqueID: MCSection::NonUniqueID); |
326 | } |
327 | |
328 | bool COFFAsmParser::parseSectionSwitch(StringRef Section, |
329 | unsigned Characteristics, |
330 | StringRef COMDATSymName, |
331 | COFF::COMDATType Type, |
332 | unsigned UniqueID) { |
333 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
334 | return TokError(Msg: "unexpected token in section switching directive" ); |
335 | Lex(); |
336 | |
337 | getStreamer().switchSection(Section: getContext().getCOFFSection( |
338 | Section, Characteristics, COMDATSymName, Selection: Type, UniqueID)); |
339 | |
340 | return false; |
341 | } |
342 | |
343 | bool COFFAsmParser::parseSectionName(StringRef &SectionName) { |
344 | if (!getLexer().is(K: AsmToken::Identifier) && !getLexer().is(K: AsmToken::String)) |
345 | return true; |
346 | |
347 | SectionName = getTok().getIdentifier(); |
348 | Lex(); |
349 | return false; |
350 | } |
351 | |
352 | bool COFFAsmParser::parseDirectiveSection(StringRef directive, SMLoc loc) { |
353 | return parseSectionArguments(directive, loc); |
354 | } |
355 | |
356 | // .section name [, "flags"] [, identifier [ identifier ], identifier] |
357 | // .pushsection <same as above> |
358 | // |
359 | // Supported flags: |
360 | // a: Ignored. |
361 | // b: BSS section (uninitialized data) |
362 | // d: data section (initialized data) |
363 | // n: "noload" section (removed by linker) |
364 | // D: Discardable section |
365 | // r: Readable section |
366 | // s: Shared section |
367 | // w: Writable section |
368 | // x: Executable section |
369 | // y: Not-readable section (clears 'r') |
370 | // |
371 | // Subsections are not supported. |
372 | bool COFFAsmParser::parseSectionArguments(StringRef, SMLoc) { |
373 | StringRef SectionName; |
374 | |
375 | if (parseSectionName(SectionName)) |
376 | return TokError(Msg: "expected identifier in directive" ); |
377 | |
378 | unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | |
379 | COFF::IMAGE_SCN_MEM_READ | |
380 | COFF::IMAGE_SCN_MEM_WRITE; |
381 | |
382 | if (getLexer().is(K: AsmToken::Comma)) { |
383 | Lex(); |
384 | |
385 | if (getLexer().isNot(K: AsmToken::String)) |
386 | return TokError(Msg: "expected string in directive" ); |
387 | |
388 | StringRef FlagsStr = getTok().getStringContents(); |
389 | Lex(); |
390 | |
391 | if (parseSectionFlags(SectionName, FlagsString: FlagsStr, Flags: &Flags)) |
392 | return true; |
393 | } |
394 | |
395 | COFF::COMDATType Type = (COFF::COMDATType)0; |
396 | StringRef COMDATSymName; |
397 | if (getLexer().is(K: AsmToken::Comma) && |
398 | getLexer().peekTok().getString() != "unique" ) { |
399 | Type = COFF::IMAGE_COMDAT_SELECT_ANY; |
400 | Lex(); |
401 | |
402 | Flags |= COFF::IMAGE_SCN_LNK_COMDAT; |
403 | |
404 | if (!getLexer().is(K: AsmToken::Identifier)) |
405 | return TokError(Msg: "expected comdat type such as 'discard' or 'largest' " |
406 | "after protection bits" ); |
407 | |
408 | if (parseCOMDATType(Type)) |
409 | return true; |
410 | |
411 | if (getLexer().isNot(K: AsmToken::Comma)) |
412 | return TokError(Msg: "expected comma in directive" ); |
413 | Lex(); |
414 | |
415 | if (getParser().parseIdentifier(Res&: COMDATSymName)) |
416 | return TokError(Msg: "expected identifier in directive" ); |
417 | } |
418 | |
419 | int64_t UniqueID = MCSection::NonUniqueID; |
420 | if (maybeParseUniqueID(UniqueID)) |
421 | return true; |
422 | |
423 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
424 | return TokError(Msg: "unexpected token in directive" ); |
425 | |
426 | if (Flags & COFF::IMAGE_SCN_CNT_CODE) { |
427 | const Triple &T = getContext().getTargetTriple(); |
428 | if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb) |
429 | Flags |= COFF::IMAGE_SCN_MEM_16BIT; |
430 | } |
431 | parseSectionSwitch(Section: SectionName, Characteristics: Flags, COMDATSymName, Type, UniqueID); |
432 | return false; |
433 | } |
434 | |
435 | bool COFFAsmParser::parseDirectivePushSection(StringRef directive, SMLoc loc) { |
436 | getStreamer().pushSection(); |
437 | |
438 | if (parseSectionArguments(directive, loc)) { |
439 | getStreamer().popSection(); |
440 | return true; |
441 | } |
442 | |
443 | return false; |
444 | } |
445 | |
446 | bool COFFAsmParser::parseDirectivePopSection(StringRef, SMLoc) { |
447 | if (!getStreamer().popSection()) |
448 | return TokError(Msg: ".popsection without corresponding .pushsection" ); |
449 | return false; |
450 | } |
451 | |
452 | bool COFFAsmParser::parseDirectiveDef(StringRef, SMLoc) { |
453 | StringRef SymbolName; |
454 | |
455 | if (getParser().parseIdentifier(Res&: SymbolName)) |
456 | return TokError(Msg: "expected identifier in directive" ); |
457 | |
458 | MCSymbol *Sym = getContext().getOrCreateSymbol(Name: SymbolName); |
459 | |
460 | getStreamer().beginCOFFSymbolDef(Symbol: Sym); |
461 | |
462 | Lex(); |
463 | return false; |
464 | } |
465 | |
466 | bool COFFAsmParser::parseDirectiveScl(StringRef, SMLoc) { |
467 | int64_t SymbolStorageClass; |
468 | if (getParser().parseAbsoluteExpression(Res&: SymbolStorageClass)) |
469 | return true; |
470 | |
471 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
472 | return TokError(Msg: "unexpected token in directive" ); |
473 | |
474 | Lex(); |
475 | getStreamer().emitCOFFSymbolStorageClass(StorageClass: SymbolStorageClass); |
476 | return false; |
477 | } |
478 | |
479 | bool COFFAsmParser::parseDirectiveType(StringRef, SMLoc) { |
480 | int64_t Type; |
481 | if (getParser().parseAbsoluteExpression(Res&: Type)) |
482 | return true; |
483 | |
484 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
485 | return TokError(Msg: "unexpected token in directive" ); |
486 | |
487 | Lex(); |
488 | getStreamer().emitCOFFSymbolType(Type); |
489 | return false; |
490 | } |
491 | |
492 | bool COFFAsmParser::parseDirectiveEndef(StringRef, SMLoc) { |
493 | Lex(); |
494 | getStreamer().endCOFFSymbolDef(); |
495 | return false; |
496 | } |
497 | |
498 | bool COFFAsmParser::parseDirectiveSecRel32(StringRef, SMLoc) { |
499 | StringRef SymbolID; |
500 | if (getParser().parseIdentifier(Res&: SymbolID)) |
501 | return TokError(Msg: "expected identifier in directive" ); |
502 | |
503 | int64_t Offset = 0; |
504 | SMLoc OffsetLoc; |
505 | if (getLexer().is(K: AsmToken::Plus)) { |
506 | OffsetLoc = getLexer().getLoc(); |
507 | if (getParser().parseAbsoluteExpression(Res&: Offset)) |
508 | return true; |
509 | } |
510 | |
511 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
512 | return TokError(Msg: "unexpected token in directive" ); |
513 | |
514 | if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max()) |
515 | return Error( |
516 | L: OffsetLoc, |
517 | Msg: "invalid '.secrel32' directive offset, can't be less " |
518 | "than zero or greater than std::numeric_limits<uint32_t>::max()" ); |
519 | |
520 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
521 | |
522 | Lex(); |
523 | getStreamer().emitCOFFSecRel32(Symbol, Offset); |
524 | return false; |
525 | } |
526 | |
527 | bool COFFAsmParser::parseDirectiveRVA(StringRef, SMLoc) { |
528 | auto parseOp = [&]() -> bool { |
529 | StringRef SymbolID; |
530 | if (getParser().parseIdentifier(Res&: SymbolID)) |
531 | return TokError(Msg: "expected identifier in directive" ); |
532 | |
533 | int64_t Offset = 0; |
534 | SMLoc OffsetLoc; |
535 | if (getLexer().is(K: AsmToken::Plus) || getLexer().is(K: AsmToken::Minus)) { |
536 | OffsetLoc = getLexer().getLoc(); |
537 | if (getParser().parseAbsoluteExpression(Res&: Offset)) |
538 | return true; |
539 | } |
540 | |
541 | if (Offset < std::numeric_limits<int32_t>::min() || |
542 | Offset > std::numeric_limits<int32_t>::max()) |
543 | return Error(L: OffsetLoc, Msg: "invalid '.rva' directive offset, can't be less " |
544 | "than -2147483648 or greater than " |
545 | "2147483647" ); |
546 | |
547 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
548 | |
549 | getStreamer().emitCOFFImgRel32(Symbol, Offset); |
550 | return false; |
551 | }; |
552 | |
553 | if (getParser().parseMany(parseOne: parseOp)) |
554 | return addErrorSuffix(Suffix: " in directive" ); |
555 | return false; |
556 | } |
557 | |
558 | bool COFFAsmParser::parseDirectiveSafeSEH(StringRef, SMLoc) { |
559 | StringRef SymbolID; |
560 | if (getParser().parseIdentifier(Res&: SymbolID)) |
561 | return TokError(Msg: "expected identifier in directive" ); |
562 | |
563 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
564 | return TokError(Msg: "unexpected token in directive" ); |
565 | |
566 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
567 | |
568 | Lex(); |
569 | getStreamer().emitCOFFSafeSEH(Symbol); |
570 | return false; |
571 | } |
572 | |
573 | bool COFFAsmParser::parseDirectiveSecIdx(StringRef, SMLoc) { |
574 | StringRef SymbolID; |
575 | if (getParser().parseIdentifier(Res&: SymbolID)) |
576 | return TokError(Msg: "expected identifier in directive" ); |
577 | |
578 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
579 | return TokError(Msg: "unexpected token in directive" ); |
580 | |
581 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
582 | |
583 | Lex(); |
584 | getStreamer().emitCOFFSectionIndex(Symbol); |
585 | return false; |
586 | } |
587 | |
588 | bool COFFAsmParser::parseDirectiveSymIdx(StringRef, SMLoc) { |
589 | StringRef SymbolID; |
590 | if (getParser().parseIdentifier(Res&: SymbolID)) |
591 | return TokError(Msg: "expected identifier in directive" ); |
592 | |
593 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
594 | return TokError(Msg: "unexpected token in directive" ); |
595 | |
596 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
597 | |
598 | Lex(); |
599 | getStreamer().emitCOFFSymbolIndex(Symbol); |
600 | return false; |
601 | } |
602 | |
603 | bool COFFAsmParser::parseDirectiveSecNum(StringRef, SMLoc) { |
604 | StringRef SymbolID; |
605 | if (getParser().parseIdentifier(Res&: SymbolID)) |
606 | return TokError(Msg: "expected identifier in directive" ); |
607 | |
608 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
609 | return TokError(Msg: "unexpected token in directive" ); |
610 | |
611 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
612 | |
613 | Lex(); |
614 | getStreamer().emitCOFFSecNumber(Symbol); |
615 | return false; |
616 | } |
617 | |
618 | bool COFFAsmParser::parseDirectiveSecOffset(StringRef, SMLoc) { |
619 | StringRef SymbolID; |
620 | if (getParser().parseIdentifier(Res&: SymbolID)) |
621 | return TokError(Msg: "expected identifier in directive" ); |
622 | |
623 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
624 | return TokError(Msg: "unexpected token in directive" ); |
625 | |
626 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
627 | |
628 | Lex(); |
629 | getStreamer().emitCOFFSecOffset(Symbol); |
630 | return false; |
631 | } |
632 | |
633 | /// ::= [ identifier ] |
634 | bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) { |
635 | StringRef TypeId = getTok().getIdentifier(); |
636 | |
637 | Type = StringSwitch<COFF::COMDATType>(TypeId) |
638 | .Case(S: "one_only" , Value: COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) |
639 | .Case(S: "discard" , Value: COFF::IMAGE_COMDAT_SELECT_ANY) |
640 | .Case(S: "same_size" , Value: COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) |
641 | .Case(S: "same_contents" , Value: COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) |
642 | .Case(S: "associative" , Value: COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) |
643 | .Case(S: "largest" , Value: COFF::IMAGE_COMDAT_SELECT_LARGEST) |
644 | .Case(S: "newest" , Value: COFF::IMAGE_COMDAT_SELECT_NEWEST) |
645 | .Default(Value: (COFF::COMDATType)0); |
646 | |
647 | if (Type == 0) |
648 | return TokError(Msg: Twine("unrecognized COMDAT type '" + TypeId + "'" )); |
649 | |
650 | Lex(); |
651 | |
652 | return false; |
653 | } |
654 | |
655 | /// ParseDirectiveLinkOnce |
656 | /// ::= .linkonce [ identifier ] |
657 | bool COFFAsmParser::parseDirectiveLinkOnce(StringRef, SMLoc Loc) { |
658 | COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; |
659 | if (getLexer().is(K: AsmToken::Identifier)) |
660 | if (parseCOMDATType(Type)) |
661 | return true; |
662 | |
663 | const MCSectionCOFF *Current = |
664 | static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly()); |
665 | |
666 | if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) |
667 | return Error(L: Loc, Msg: "cannot make section associative with .linkonce" ); |
668 | |
669 | if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) |
670 | return Error(L: Loc, Msg: Twine("section '" ) + Current->getName() + |
671 | "' is already linkonce" ); |
672 | |
673 | Current->setSelection(Type); |
674 | |
675 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
676 | return TokError(Msg: "unexpected token in directive" ); |
677 | |
678 | return false; |
679 | } |
680 | |
681 | bool COFFAsmParser::parseSEHDirectiveStartProc(StringRef, SMLoc Loc) { |
682 | StringRef SymbolID; |
683 | if (getParser().parseIdentifier(Res&: SymbolID)) |
684 | return true; |
685 | |
686 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
687 | return TokError(Msg: "unexpected token in directive" ); |
688 | |
689 | MCSymbol *Symbol = getContext().getOrCreateSymbol(Name: SymbolID); |
690 | |
691 | Lex(); |
692 | getStreamer().emitWinCFIStartProc(Symbol, Loc); |
693 | return false; |
694 | } |
695 | |
696 | bool COFFAsmParser::parseSEHDirectiveEndProc(StringRef, SMLoc Loc) { |
697 | Lex(); |
698 | getStreamer().emitWinCFIEndProc(Loc); |
699 | return false; |
700 | } |
701 | |
702 | bool COFFAsmParser::parseSEHDirectiveEndFuncletOrFunc(StringRef, SMLoc Loc) { |
703 | Lex(); |
704 | getStreamer().emitWinCFIFuncletOrFuncEnd(Loc); |
705 | return false; |
706 | } |
707 | |
708 | bool COFFAsmParser::parseSEHDirectiveStartChained(StringRef, SMLoc Loc) { |
709 | Lex(); |
710 | getStreamer().emitWinCFIStartChained(Loc); |
711 | return false; |
712 | } |
713 | |
714 | bool COFFAsmParser::parseSEHDirectiveEndChained(StringRef, SMLoc Loc) { |
715 | Lex(); |
716 | getStreamer().emitWinCFIEndChained(Loc); |
717 | return false; |
718 | } |
719 | |
720 | bool COFFAsmParser::parseSEHDirectiveHandler(StringRef, SMLoc Loc) { |
721 | StringRef SymbolID; |
722 | if (getParser().parseIdentifier(Res&: SymbolID)) |
723 | return true; |
724 | |
725 | if (getLexer().isNot(K: AsmToken::Comma)) |
726 | return TokError(Msg: "you must specify one or both of @unwind or @except" ); |
727 | Lex(); |
728 | bool unwind = false, except = false; |
729 | if (parseAtUnwindOrAtExcept(unwind, except)) |
730 | return true; |
731 | if (getLexer().is(K: AsmToken::Comma)) { |
732 | Lex(); |
733 | if (parseAtUnwindOrAtExcept(unwind, except)) |
734 | return true; |
735 | } |
736 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
737 | return TokError(Msg: "unexpected token in directive" ); |
738 | |
739 | MCSymbol *handler = getContext().getOrCreateSymbol(Name: SymbolID); |
740 | |
741 | Lex(); |
742 | getStreamer().emitWinEHHandler(Sym: handler, Unwind: unwind, Except: except, Loc); |
743 | return false; |
744 | } |
745 | |
746 | bool COFFAsmParser::parseSEHDirectiveHandlerData(StringRef, SMLoc Loc) { |
747 | Lex(); |
748 | getStreamer().emitWinEHHandlerData(); |
749 | return false; |
750 | } |
751 | |
752 | bool COFFAsmParser::parseSEHDirectiveAllocStack(StringRef, SMLoc Loc) { |
753 | int64_t Size; |
754 | if (getParser().parseAbsoluteExpression(Res&: Size)) |
755 | return true; |
756 | |
757 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
758 | return TokError(Msg: "unexpected token in directive" ); |
759 | |
760 | Lex(); |
761 | getStreamer().emitWinCFIAllocStack(Size, Loc); |
762 | return false; |
763 | } |
764 | |
765 | bool COFFAsmParser::parseSEHDirectiveEndProlog(StringRef, SMLoc Loc) { |
766 | Lex(); |
767 | getStreamer().emitWinCFIEndProlog(Loc); |
768 | return false; |
769 | } |
770 | |
771 | bool COFFAsmParser::ParseSEHDirectiveBeginEpilog(StringRef, SMLoc Loc) { |
772 | Lex(); |
773 | getStreamer().emitWinCFIBeginEpilogue(Loc); |
774 | return false; |
775 | } |
776 | |
777 | bool COFFAsmParser::ParseSEHDirectiveEndEpilog(StringRef, SMLoc Loc) { |
778 | Lex(); |
779 | getStreamer().emitWinCFIEndEpilogue(Loc); |
780 | return false; |
781 | } |
782 | |
783 | bool COFFAsmParser::ParseSEHDirectiveUnwindV2Start(StringRef, SMLoc Loc) { |
784 | Lex(); |
785 | getStreamer().emitWinCFIUnwindV2Start(Loc); |
786 | return false; |
787 | } |
788 | |
789 | bool COFFAsmParser::ParseSEHDirectiveUnwindVersion(StringRef, SMLoc Loc) { |
790 | int64_t Version; |
791 | if (getParser().parseIntToken(V&: Version, ErrMsg: "expected unwind version number" )) |
792 | return true; |
793 | |
794 | if ((Version < 1) || (Version > UINT8_MAX)) |
795 | return Error(L: Loc, Msg: "invalid unwind version" ); |
796 | |
797 | if (getLexer().isNot(K: AsmToken::EndOfStatement)) |
798 | return TokError(Msg: "unexpected token in directive" ); |
799 | |
800 | Lex(); |
801 | getStreamer().emitWinCFIUnwindVersion(Version, Loc); |
802 | return false; |
803 | } |
804 | |
805 | bool COFFAsmParser::parseAtUnwindOrAtExcept(bool &unwind, bool &except) { |
806 | StringRef identifier; |
807 | if (getLexer().isNot(K: AsmToken::At) && getLexer().isNot(K: AsmToken::Percent)) |
808 | return TokError(Msg: "a handler attribute must begin with '@' or '%'" ); |
809 | SMLoc startLoc = getLexer().getLoc(); |
810 | Lex(); |
811 | if (getParser().parseIdentifier(Res&: identifier)) |
812 | return Error(L: startLoc, Msg: "expected @unwind or @except" ); |
813 | if (identifier == "unwind" ) |
814 | unwind = true; |
815 | else if (identifier == "except" ) |
816 | except = true; |
817 | else |
818 | return Error(L: startLoc, Msg: "expected @unwind or @except" ); |
819 | return false; |
820 | } |
821 | |
822 | namespace llvm { |
823 | |
824 | MCAsmParserExtension *createCOFFAsmParser() { |
825 | return new COFFAsmParser; |
826 | } |
827 | |
828 | } // end namespace llvm |
829 | |