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