1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/BinaryFormat/COFF.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCDirectives.h"
17 #include "llvm/MC/MCObjectFileInfo.h"
18 #include "llvm/MC/MCParser/MCAsmLexer.h"
19 #include "llvm/MC/MCParser/MCAsmParserExtension.h"
20 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
21 #include "llvm/MC/MCRegisterInfo.h"
22 #include "llvm/MC/MCSectionCOFF.h"
23 #include "llvm/MC/MCStreamer.h"
24 #include "llvm/MC/SectionKind.h"
25 #include "llvm/Support/SMLoc.h"
26 #include <cassert>
27 #include <cstdint>
28 #include <limits>
29 #include <utility>
30
31 using namespace llvm;
32
33 namespace {
34
35 class COFFAsmParser : public MCAsmParserExtension {
36 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)37 void addDirectiveHandler(StringRef Directive) {
38 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
39 this, HandleDirective<COFFAsmParser, HandlerMethod>);
40 getParser().addDirectiveHandler(Directive, Handler);
41 }
42
43 bool ParseSectionSwitch(StringRef Section,
44 unsigned Characteristics,
45 SectionKind Kind);
46
47 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
48 SectionKind Kind, StringRef COMDATSymName,
49 COFF::COMDATType Type);
50
51 bool ParseSectionName(StringRef &SectionName);
52 bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
53 unsigned *Flags);
54
Initialize(MCAsmParser & Parser)55 void Initialize(MCAsmParser &Parser) override {
56 // Call the base implementation.
57 MCAsmParserExtension::Initialize(Parser);
58
59 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
60 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
61 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
62 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
63 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
64 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
65 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
66 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
67 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
68 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
69 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
70 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
71 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
72 addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
73
74 // Win64 EH directives.
75 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
76 ".seh_proc");
77 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
78 ".seh_endproc");
79 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
80 ".seh_startchained");
81 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
82 ".seh_endchained");
83 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
84 ".seh_handler");
85 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
86 ".seh_handlerdata");
87 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
88 ".seh_pushreg");
89 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
90 ".seh_setframe");
91 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
92 ".seh_stackalloc");
93 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
94 ".seh_savereg");
95 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
96 ".seh_savexmm");
97 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
98 ".seh_pushframe");
99 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
100 ".seh_endprologue");
101 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
102 }
103
ParseSectionDirectiveText(StringRef,SMLoc)104 bool ParseSectionDirectiveText(StringRef, SMLoc) {
105 return ParseSectionSwitch(".text",
106 COFF::IMAGE_SCN_CNT_CODE
107 | COFF::IMAGE_SCN_MEM_EXECUTE
108 | COFF::IMAGE_SCN_MEM_READ,
109 SectionKind::getText());
110 }
111
ParseSectionDirectiveData(StringRef,SMLoc)112 bool ParseSectionDirectiveData(StringRef, SMLoc) {
113 return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
114 COFF::IMAGE_SCN_MEM_READ |
115 COFF::IMAGE_SCN_MEM_WRITE,
116 SectionKind::getData());
117 }
118
ParseSectionDirectiveBSS(StringRef,SMLoc)119 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
120 return ParseSectionSwitch(".bss",
121 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
122 | COFF::IMAGE_SCN_MEM_READ
123 | COFF::IMAGE_SCN_MEM_WRITE,
124 SectionKind::getBSS());
125 }
126
127 bool ParseDirectiveSection(StringRef, SMLoc);
128 bool ParseDirectiveDef(StringRef, SMLoc);
129 bool ParseDirectiveScl(StringRef, SMLoc);
130 bool ParseDirectiveType(StringRef, SMLoc);
131 bool ParseDirectiveEndef(StringRef, SMLoc);
132 bool ParseDirectiveSecRel32(StringRef, SMLoc);
133 bool ParseDirectiveSecIdx(StringRef, SMLoc);
134 bool ParseDirectiveSafeSEH(StringRef, SMLoc);
135 bool ParseDirectiveSymIdx(StringRef, SMLoc);
136 bool parseCOMDATType(COFF::COMDATType &Type);
137 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
138 bool ParseDirectiveRVA(StringRef, SMLoc);
139
140 // Win64 EH directives.
141 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
142 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
143 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
144 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
145 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
146 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
147 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
148 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
149 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
150 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
151 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
152 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
153 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
154
155 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
156 bool ParseSEHRegisterNumber(unsigned &RegNo);
157 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
158
159 public:
160 COFFAsmParser() = default;
161 };
162
163 } // end annonomous namespace.
164
computeSectionKind(unsigned Flags)165 static SectionKind computeSectionKind(unsigned Flags) {
166 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
167 return SectionKind::getText();
168 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
169 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
170 return SectionKind::getReadOnly();
171 return SectionKind::getData();
172 }
173
ParseSectionFlags(StringRef SectionName,StringRef FlagsString,unsigned * Flags)174 bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
175 StringRef FlagsString, unsigned *Flags) {
176 enum {
177 None = 0,
178 Alloc = 1 << 0,
179 Code = 1 << 1,
180 Load = 1 << 2,
181 InitData = 1 << 3,
182 Shared = 1 << 4,
183 NoLoad = 1 << 5,
184 NoRead = 1 << 6,
185 NoWrite = 1 << 7,
186 Discardable = 1 << 8,
187 };
188
189 bool ReadOnlyRemoved = false;
190 unsigned SecFlags = None;
191
192 for (char FlagChar : FlagsString) {
193 switch (FlagChar) {
194 case 'a':
195 // Ignored.
196 break;
197
198 case 'b': // bss section
199 SecFlags |= Alloc;
200 if (SecFlags & InitData)
201 return TokError("conflicting section flags 'b' and 'd'.");
202 SecFlags &= ~Load;
203 break;
204
205 case 'd': // data section
206 SecFlags |= InitData;
207 if (SecFlags & Alloc)
208 return TokError("conflicting section flags 'b' and 'd'.");
209 SecFlags &= ~NoWrite;
210 if ((SecFlags & NoLoad) == 0)
211 SecFlags |= Load;
212 break;
213
214 case 'n': // section is not loaded
215 SecFlags |= NoLoad;
216 SecFlags &= ~Load;
217 break;
218
219 case 'D': // discardable
220 SecFlags |= Discardable;
221 break;
222
223 case 'r': // read-only
224 ReadOnlyRemoved = false;
225 SecFlags |= NoWrite;
226 if ((SecFlags & Code) == 0)
227 SecFlags |= InitData;
228 if ((SecFlags & NoLoad) == 0)
229 SecFlags |= Load;
230 break;
231
232 case 's': // shared section
233 SecFlags |= Shared | InitData;
234 SecFlags &= ~NoWrite;
235 if ((SecFlags & NoLoad) == 0)
236 SecFlags |= Load;
237 break;
238
239 case 'w': // writable
240 SecFlags &= ~NoWrite;
241 ReadOnlyRemoved = true;
242 break;
243
244 case 'x': // executable section
245 SecFlags |= Code;
246 if ((SecFlags & NoLoad) == 0)
247 SecFlags |= Load;
248 if (!ReadOnlyRemoved)
249 SecFlags |= NoWrite;
250 break;
251
252 case 'y': // not readable
253 SecFlags |= NoRead | NoWrite;
254 break;
255
256 default:
257 return TokError("unknown flag");
258 }
259 }
260
261 *Flags = 0;
262
263 if (SecFlags == None)
264 SecFlags = InitData;
265
266 if (SecFlags & Code)
267 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
268 if (SecFlags & InitData)
269 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
270 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
271 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
272 if (SecFlags & NoLoad)
273 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
274 if ((SecFlags & Discardable) ||
275 MCSectionCOFF::isImplicitlyDiscardable(SectionName))
276 *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
277 if ((SecFlags & NoRead) == 0)
278 *Flags |= COFF::IMAGE_SCN_MEM_READ;
279 if ((SecFlags & NoWrite) == 0)
280 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
281 if (SecFlags & Shared)
282 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
283
284 return false;
285 }
286
287 /// ParseDirectiveSymbolAttribute
288 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
ParseDirectiveSymbolAttribute(StringRef Directive,SMLoc)289 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
290 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
291 .Case(".weak", MCSA_Weak)
292 .Default(MCSA_Invalid);
293 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
294 if (getLexer().isNot(AsmToken::EndOfStatement)) {
295 while (true) {
296 StringRef Name;
297
298 if (getParser().parseIdentifier(Name))
299 return TokError("expected identifier in directive");
300
301 MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
302
303 getStreamer().EmitSymbolAttribute(Sym, Attr);
304
305 if (getLexer().is(AsmToken::EndOfStatement))
306 break;
307
308 if (getLexer().isNot(AsmToken::Comma))
309 return TokError("unexpected token in directive");
310 Lex();
311 }
312 }
313
314 Lex();
315 return false;
316 }
317
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind)318 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
319 unsigned Characteristics,
320 SectionKind Kind) {
321 return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
322 }
323
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind,StringRef COMDATSymName,COFF::COMDATType Type)324 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
325 unsigned Characteristics,
326 SectionKind Kind,
327 StringRef COMDATSymName,
328 COFF::COMDATType Type) {
329 if (getLexer().isNot(AsmToken::EndOfStatement))
330 return TokError("unexpected token in section switching directive");
331 Lex();
332
333 getStreamer().SwitchSection(getContext().getCOFFSection(
334 Section, Characteristics, Kind, COMDATSymName, Type));
335
336 return false;
337 }
338
ParseSectionName(StringRef & SectionName)339 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
340 if (!getLexer().is(AsmToken::Identifier))
341 return true;
342
343 SectionName = getTok().getIdentifier();
344 Lex();
345 return false;
346 }
347
348 // .section name [, "flags"] [, identifier [ identifier ], identifier]
349 //
350 // Supported flags:
351 // a: Ignored.
352 // b: BSS section (uninitialized data)
353 // d: data section (initialized data)
354 // n: "noload" section (removed by linker)
355 // D: Discardable section
356 // r: Readable section
357 // s: Shared section
358 // w: Writable section
359 // x: Executable section
360 // y: Not-readable section (clears 'r')
361 //
362 // Subsections are not supported.
ParseDirectiveSection(StringRef,SMLoc)363 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
364 StringRef SectionName;
365
366 if (ParseSectionName(SectionName))
367 return TokError("expected identifier in directive");
368
369 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
370 COFF::IMAGE_SCN_MEM_READ |
371 COFF::IMAGE_SCN_MEM_WRITE;
372
373 if (getLexer().is(AsmToken::Comma)) {
374 Lex();
375
376 if (getLexer().isNot(AsmToken::String))
377 return TokError("expected string in directive");
378
379 StringRef FlagsStr = getTok().getStringContents();
380 Lex();
381
382 if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
383 return true;
384 }
385
386 COFF::COMDATType Type = (COFF::COMDATType)0;
387 StringRef COMDATSymName;
388 if (getLexer().is(AsmToken::Comma)) {
389 Type = COFF::IMAGE_COMDAT_SELECT_ANY;
390 Lex();
391
392 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
393
394 if (!getLexer().is(AsmToken::Identifier))
395 return TokError("expected comdat type such as 'discard' or 'largest' "
396 "after protection bits");
397
398 if (parseCOMDATType(Type))
399 return true;
400
401 if (getLexer().isNot(AsmToken::Comma))
402 return TokError("expected comma in directive");
403 Lex();
404
405 if (getParser().parseIdentifier(COMDATSymName))
406 return TokError("expected identifier in directive");
407 }
408
409 if (getLexer().isNot(AsmToken::EndOfStatement))
410 return TokError("unexpected token in directive");
411
412 SectionKind Kind = computeSectionKind(Flags);
413 if (Kind.isText()) {
414 const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
415 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
416 Flags |= COFF::IMAGE_SCN_MEM_16BIT;
417 }
418 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
419 return false;
420 }
421
ParseDirectiveDef(StringRef,SMLoc)422 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
423 StringRef SymbolName;
424
425 if (getParser().parseIdentifier(SymbolName))
426 return TokError("expected identifier in directive");
427
428 MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
429
430 getStreamer().BeginCOFFSymbolDef(Sym);
431
432 Lex();
433 return false;
434 }
435
ParseDirectiveScl(StringRef,SMLoc)436 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
437 int64_t SymbolStorageClass;
438 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
439 return true;
440
441 if (getLexer().isNot(AsmToken::EndOfStatement))
442 return TokError("unexpected token in directive");
443
444 Lex();
445 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
446 return false;
447 }
448
ParseDirectiveType(StringRef,SMLoc)449 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
450 int64_t Type;
451 if (getParser().parseAbsoluteExpression(Type))
452 return true;
453
454 if (getLexer().isNot(AsmToken::EndOfStatement))
455 return TokError("unexpected token in directive");
456
457 Lex();
458 getStreamer().EmitCOFFSymbolType(Type);
459 return false;
460 }
461
ParseDirectiveEndef(StringRef,SMLoc)462 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
463 Lex();
464 getStreamer().EndCOFFSymbolDef();
465 return false;
466 }
467
ParseDirectiveSecRel32(StringRef,SMLoc)468 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
469 StringRef SymbolID;
470 if (getParser().parseIdentifier(SymbolID))
471 return TokError("expected identifier in directive");
472
473 int64_t Offset = 0;
474 SMLoc OffsetLoc;
475 if (getLexer().is(AsmToken::Plus)) {
476 OffsetLoc = getLexer().getLoc();
477 if (getParser().parseAbsoluteExpression(Offset))
478 return true;
479 }
480
481 if (getLexer().isNot(AsmToken::EndOfStatement))
482 return TokError("unexpected token in directive");
483
484 if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
485 return Error(
486 OffsetLoc,
487 "invalid '.secrel32' directive offset, can't be less "
488 "than zero or greater than std::numeric_limits<uint32_t>::max()");
489
490 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
491
492 Lex();
493 getStreamer().EmitCOFFSecRel32(Symbol, Offset);
494 return false;
495 }
496
ParseDirectiveRVA(StringRef,SMLoc)497 bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
498 auto parseOp = [&]() -> bool {
499 StringRef SymbolID;
500 if (getParser().parseIdentifier(SymbolID))
501 return TokError("expected identifier in directive");
502
503 int64_t Offset = 0;
504 SMLoc OffsetLoc;
505 if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
506 OffsetLoc = getLexer().getLoc();
507 if (getParser().parseAbsoluteExpression(Offset))
508 return true;
509 }
510
511 if (Offset < std::numeric_limits<int32_t>::min() ||
512 Offset > std::numeric_limits<int32_t>::max())
513 return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
514 "than -2147483648 or greater than "
515 "2147483647");
516
517 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
518
519 getStreamer().EmitCOFFImgRel32(Symbol, Offset);
520 return false;
521 };
522
523 if (getParser().parseMany(parseOp))
524 return addErrorSuffix(" in directive");
525 return false;
526 }
527
ParseDirectiveSafeSEH(StringRef,SMLoc)528 bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
529 StringRef SymbolID;
530 if (getParser().parseIdentifier(SymbolID))
531 return TokError("expected identifier in directive");
532
533 if (getLexer().isNot(AsmToken::EndOfStatement))
534 return TokError("unexpected token in directive");
535
536 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
537
538 Lex();
539 getStreamer().EmitCOFFSafeSEH(Symbol);
540 return false;
541 }
542
ParseDirectiveSecIdx(StringRef,SMLoc)543 bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
544 StringRef SymbolID;
545 if (getParser().parseIdentifier(SymbolID))
546 return TokError("expected identifier in directive");
547
548 if (getLexer().isNot(AsmToken::EndOfStatement))
549 return TokError("unexpected token in directive");
550
551 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
552
553 Lex();
554 getStreamer().EmitCOFFSectionIndex(Symbol);
555 return false;
556 }
557
ParseDirectiveSymIdx(StringRef,SMLoc)558 bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
559 StringRef SymbolID;
560 if (getParser().parseIdentifier(SymbolID))
561 return TokError("expected identifier in directive");
562
563 if (getLexer().isNot(AsmToken::EndOfStatement))
564 return TokError("unexpected token in directive");
565
566 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
567
568 Lex();
569 getStreamer().EmitCOFFSymbolIndex(Symbol);
570 return false;
571 }
572
573 /// ::= [ identifier ]
parseCOMDATType(COFF::COMDATType & Type)574 bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
575 StringRef TypeId = getTok().getIdentifier();
576
577 Type = StringSwitch<COFF::COMDATType>(TypeId)
578 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
579 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
580 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
581 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
582 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
583 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
584 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
585 .Default((COFF::COMDATType)0);
586
587 if (Type == 0)
588 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
589
590 Lex();
591
592 return false;
593 }
594
595 /// ParseDirectiveLinkOnce
596 /// ::= .linkonce [ identifier ]
ParseDirectiveLinkOnce(StringRef,SMLoc Loc)597 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
598 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
599 if (getLexer().is(AsmToken::Identifier))
600 if (parseCOMDATType(Type))
601 return true;
602
603 const MCSectionCOFF *Current =
604 static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
605
606 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
607 return Error(Loc, "cannot make section associative with .linkonce");
608
609 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
610 return Error(Loc, Twine("section '") + Current->getSectionName() +
611 "' is already linkonce");
612
613 Current->setSelection(Type);
614
615 if (getLexer().isNot(AsmToken::EndOfStatement))
616 return TokError("unexpected token in directive");
617
618 return false;
619 }
620
ParseSEHDirectiveStartProc(StringRef,SMLoc Loc)621 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
622 StringRef SymbolID;
623 if (getParser().parseIdentifier(SymbolID))
624 return true;
625
626 if (getLexer().isNot(AsmToken::EndOfStatement))
627 return TokError("unexpected token in directive");
628
629 MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
630
631 Lex();
632 getStreamer().EmitWinCFIStartProc(Symbol, Loc);
633 return false;
634 }
635
ParseSEHDirectiveEndProc(StringRef,SMLoc Loc)636 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
637 Lex();
638 getStreamer().EmitWinCFIEndProc(Loc);
639 return false;
640 }
641
ParseSEHDirectiveStartChained(StringRef,SMLoc Loc)642 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
643 Lex();
644 getStreamer().EmitWinCFIStartChained(Loc);
645 return false;
646 }
647
ParseSEHDirectiveEndChained(StringRef,SMLoc Loc)648 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
649 Lex();
650 getStreamer().EmitWinCFIEndChained(Loc);
651 return false;
652 }
653
ParseSEHDirectiveHandler(StringRef,SMLoc Loc)654 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
655 StringRef SymbolID;
656 if (getParser().parseIdentifier(SymbolID))
657 return true;
658
659 if (getLexer().isNot(AsmToken::Comma))
660 return TokError("you must specify one or both of @unwind or @except");
661 Lex();
662 bool unwind = false, except = false;
663 if (ParseAtUnwindOrAtExcept(unwind, except))
664 return true;
665 if (getLexer().is(AsmToken::Comma)) {
666 Lex();
667 if (ParseAtUnwindOrAtExcept(unwind, except))
668 return true;
669 }
670 if (getLexer().isNot(AsmToken::EndOfStatement))
671 return TokError("unexpected token in directive");
672
673 MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
674
675 Lex();
676 getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
677 return false;
678 }
679
ParseSEHDirectiveHandlerData(StringRef,SMLoc Loc)680 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
681 Lex();
682 getStreamer().EmitWinEHHandlerData();
683 return false;
684 }
685
ParseSEHDirectivePushReg(StringRef,SMLoc Loc)686 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) {
687 unsigned Reg = 0;
688 if (ParseSEHRegisterNumber(Reg))
689 return true;
690
691 if (getLexer().isNot(AsmToken::EndOfStatement))
692 return TokError("unexpected token in directive");
693
694 Lex();
695 getStreamer().EmitWinCFIPushReg(Reg, Loc);
696 return false;
697 }
698
ParseSEHDirectiveSetFrame(StringRef,SMLoc Loc)699 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) {
700 unsigned Reg = 0;
701 int64_t Off;
702 if (ParseSEHRegisterNumber(Reg))
703 return true;
704 if (getLexer().isNot(AsmToken::Comma))
705 return TokError("you must specify a stack pointer offset");
706
707 Lex();
708 if (getParser().parseAbsoluteExpression(Off))
709 return true;
710
711 if (getLexer().isNot(AsmToken::EndOfStatement))
712 return TokError("unexpected token in directive");
713
714 Lex();
715 getStreamer().EmitWinCFISetFrame(Reg, Off, Loc);
716 return false;
717 }
718
ParseSEHDirectiveAllocStack(StringRef,SMLoc Loc)719 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
720 int64_t Size;
721 if (getParser().parseAbsoluteExpression(Size))
722 return true;
723
724 if (getLexer().isNot(AsmToken::EndOfStatement))
725 return TokError("unexpected token in directive");
726
727 Lex();
728 getStreamer().EmitWinCFIAllocStack(Size, Loc);
729 return false;
730 }
731
ParseSEHDirectiveSaveReg(StringRef,SMLoc Loc)732 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) {
733 unsigned Reg = 0;
734 int64_t Off;
735 if (ParseSEHRegisterNumber(Reg))
736 return true;
737 if (getLexer().isNot(AsmToken::Comma))
738 return TokError("you must specify an offset on the stack");
739
740 Lex();
741 if (getParser().parseAbsoluteExpression(Off))
742 return true;
743
744 if (getLexer().isNot(AsmToken::EndOfStatement))
745 return TokError("unexpected token in directive");
746
747 Lex();
748 // FIXME: Err on %xmm* registers
749 getStreamer().EmitWinCFISaveReg(Reg, Off, Loc);
750 return false;
751 }
752
753 // FIXME: This method is inherently x86-specific. It should really be in the
754 // x86 backend.
ParseSEHDirectiveSaveXMM(StringRef,SMLoc Loc)755 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) {
756 unsigned Reg = 0;
757 int64_t Off;
758 if (ParseSEHRegisterNumber(Reg))
759 return true;
760 if (getLexer().isNot(AsmToken::Comma))
761 return TokError("you must specify an offset on the stack");
762
763 Lex();
764 if (getParser().parseAbsoluteExpression(Off))
765 return true;
766
767 if (getLexer().isNot(AsmToken::EndOfStatement))
768 return TokError("unexpected token in directive");
769
770 Lex();
771 // FIXME: Err on non-%xmm* registers
772 getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc);
773 return false;
774 }
775
ParseSEHDirectivePushFrame(StringRef,SMLoc Loc)776 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) {
777 bool Code = false;
778 StringRef CodeID;
779 if (getLexer().is(AsmToken::At)) {
780 SMLoc startLoc = getLexer().getLoc();
781 Lex();
782 if (!getParser().parseIdentifier(CodeID)) {
783 if (CodeID != "code")
784 return Error(startLoc, "expected @code");
785 Code = true;
786 }
787 }
788
789 if (getLexer().isNot(AsmToken::EndOfStatement))
790 return TokError("unexpected token in directive");
791
792 Lex();
793 getStreamer().EmitWinCFIPushFrame(Code, Loc);
794 return false;
795 }
796
ParseSEHDirectiveEndProlog(StringRef,SMLoc Loc)797 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
798 Lex();
799 getStreamer().EmitWinCFIEndProlog(Loc);
800 return false;
801 }
802
ParseAtUnwindOrAtExcept(bool & unwind,bool & except)803 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
804 StringRef identifier;
805 if (getLexer().isNot(AsmToken::At))
806 return TokError("a handler attribute must begin with '@'");
807 SMLoc startLoc = getLexer().getLoc();
808 Lex();
809 if (getParser().parseIdentifier(identifier))
810 return Error(startLoc, "expected @unwind or @except");
811 if (identifier == "unwind")
812 unwind = true;
813 else if (identifier == "except")
814 except = true;
815 else
816 return Error(startLoc, "expected @unwind or @except");
817 return false;
818 }
819
ParseSEHRegisterNumber(unsigned & RegNo)820 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
821 SMLoc startLoc = getLexer().getLoc();
822 if (getLexer().is(AsmToken::Percent)) {
823 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
824 SMLoc endLoc;
825 unsigned LLVMRegNo;
826 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
827 return true;
828
829 #if 0
830 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
831 // violation so this validation code is disabled.
832
833 // Check that this is a non-volatile register.
834 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
835 unsigned i;
836 for (i = 0; NVRegs[i] != 0; ++i)
837 if (NVRegs[i] == LLVMRegNo)
838 break;
839 if (NVRegs[i] == 0)
840 return Error(startLoc, "expected non-volatile register");
841 #endif
842
843 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
844 if (SEHRegNo < 0)
845 return Error(startLoc,"register can't be represented in SEH unwind info");
846 RegNo = SEHRegNo;
847 }
848 else {
849 int64_t n;
850 if (getParser().parseAbsoluteExpression(n))
851 return true;
852 if (n > 15)
853 return Error(startLoc, "register number is too high");
854 RegNo = n;
855 }
856
857 return false;
858 }
859
860 namespace llvm {
861
createCOFFAsmParser()862 MCAsmParserExtension *createCOFFAsmParser() {
863 return new COFFAsmParser;
864 }
865
866 } // end namespace llvm
867