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