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