1 //===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCRegisterInfo.h"
18 #include "llvm/MC/MCSectionCOFF.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCTargetAsmParser.h"
21 #include "llvm/Support/COFF.h"
26 class COFFAsmParser : public MCAsmParserExtension {
27 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
28 void addDirectiveHandler(StringRef Directive) {
29 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30 this, HandleDirective<COFFAsmParser, HandlerMethod>);
31 getParser().addDirectiveHandler(Directive, Handler);
34 bool ParseSectionSwitch(StringRef Section,
35 unsigned Characteristics,
38 bool ParseSectionName(StringRef &SectionName);
39 bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
41 virtual void Initialize(MCAsmParser &Parser) {
42 // Call the base implementation.
43 MCAsmParserExtension::Initialize(Parser);
45 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
46 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
47 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
48 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
49 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
50 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
51 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
52 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
53 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
54 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
56 // Win64 EH directives.
57 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
59 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
61 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
63 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
65 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
67 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
69 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
71 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
73 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
75 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
77 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
79 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
81 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
83 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
86 bool ParseSectionDirectiveText(StringRef, SMLoc) {
87 return ParseSectionSwitch(".text",
88 COFF::IMAGE_SCN_CNT_CODE
89 | COFF::IMAGE_SCN_MEM_EXECUTE
90 | COFF::IMAGE_SCN_MEM_READ,
91 SectionKind::getText());
93 bool ParseSectionDirectiveData(StringRef, SMLoc) {
94 return ParseSectionSwitch(".data",
95 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
96 | COFF::IMAGE_SCN_MEM_READ
97 | COFF::IMAGE_SCN_MEM_WRITE,
98 SectionKind::getDataRel());
100 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
101 return ParseSectionSwitch(".bss",
102 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
103 | COFF::IMAGE_SCN_MEM_READ
104 | COFF::IMAGE_SCN_MEM_WRITE,
105 SectionKind::getBSS());
108 bool ParseDirectiveSection(StringRef, SMLoc);
109 bool ParseDirectiveDef(StringRef, SMLoc);
110 bool ParseDirectiveScl(StringRef, SMLoc);
111 bool ParseDirectiveType(StringRef, SMLoc);
112 bool ParseDirectiveEndef(StringRef, SMLoc);
113 bool ParseDirectiveSecRel32(StringRef, SMLoc);
114 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
116 // Win64 EH directives.
117 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
118 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
119 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
120 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
121 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
122 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
123 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
124 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
125 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
126 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
127 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
128 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
129 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
131 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
132 bool ParseSEHRegisterNumber(unsigned &RegNo);
133 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
138 } // end annonomous namespace.
140 static SectionKind computeSectionKind(unsigned Flags) {
141 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
142 return SectionKind::getText();
143 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
144 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
145 return SectionKind::getReadOnly();
146 return SectionKind::getDataRel();
149 bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
162 bool ReadOnlyRemoved = false;
163 unsigned SecFlags = None;
165 for (unsigned i = 0; i < FlagsString.size(); ++i) {
166 switch (FlagsString[i]) {
171 case 'b': // bss section
173 if (SecFlags & InitData)
174 return TokError("conflicting section flags 'b' and 'd'.");
178 case 'd': // data section
179 SecFlags |= InitData;
180 if (SecFlags & Alloc)
181 return TokError("conflicting section flags 'b' and 'd'.");
182 SecFlags &= ~NoWrite;
183 if ((SecFlags & NoLoad) == 0)
187 case 'n': // section is not loaded
192 case 'r': // read-only
193 ReadOnlyRemoved = false;
195 if ((SecFlags & Code) == 0)
196 SecFlags |= InitData;
197 if ((SecFlags & NoLoad) == 0)
201 case 's': // shared section
202 SecFlags |= Shared | InitData;
203 SecFlags &= ~NoWrite;
204 if ((SecFlags & NoLoad) == 0)
208 case 'w': // writable
209 SecFlags &= ~NoWrite;
210 ReadOnlyRemoved = true;
213 case 'x': // executable section
215 if ((SecFlags & NoLoad) == 0)
217 if (!ReadOnlyRemoved)
221 case 'y': // not readable
222 SecFlags |= NoRead | NoWrite;
226 return TokError("unknown flag");
232 if (SecFlags == None)
236 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
237 if (SecFlags & InitData)
238 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
239 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
240 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
241 if (SecFlags & NoLoad)
242 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
243 if ((SecFlags & NoRead) == 0)
244 *Flags |= COFF::IMAGE_SCN_MEM_READ;
245 if ((SecFlags & NoWrite) == 0)
246 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
247 if (SecFlags & Shared)
248 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
253 /// ParseDirectiveSymbolAttribute
254 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
255 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
256 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
257 .Case(".weak", MCSA_Weak)
258 .Default(MCSA_Invalid);
259 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
260 if (getLexer().isNot(AsmToken::EndOfStatement)) {
264 if (getParser().parseIdentifier(Name))
265 return TokError("expected identifier in directive");
267 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
269 getStreamer().EmitSymbolAttribute(Sym, Attr);
271 if (getLexer().is(AsmToken::EndOfStatement))
274 if (getLexer().isNot(AsmToken::Comma))
275 return TokError("unexpected token in directive");
284 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
285 unsigned Characteristics,
287 if (getLexer().isNot(AsmToken::EndOfStatement))
288 return TokError("unexpected token in section switching directive");
291 getStreamer().SwitchSection(getContext().getCOFFSection(
292 Section, Characteristics, Kind));
297 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
298 if (!getLexer().is(AsmToken::Identifier))
301 SectionName = getTok().getIdentifier();
306 // .section name [, "flags"]
310 // b: BSS section (uninitialized data)
311 // d: data section (initialized data)
312 // n: Discardable section
313 // r: Readable section
315 // w: Writable section
316 // x: Executable section
317 // y: Not-readable section (clears 'r')
319 // Subsections are not supported.
320 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
321 StringRef SectionName;
323 if (ParseSectionName(SectionName))
324 return TokError("expected identifier in directive");
326 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
327 COFF::IMAGE_SCN_MEM_READ |
328 COFF::IMAGE_SCN_MEM_WRITE;
330 if (getLexer().is(AsmToken::Comma)) {
333 if (getLexer().isNot(AsmToken::String))
334 return TokError("expected string in directive");
336 StringRef FlagsStr = getTok().getStringContents();
339 if (ParseSectionFlags(FlagsStr, &Flags))
343 if (getLexer().isNot(AsmToken::EndOfStatement))
344 return TokError("unexpected token in directive");
346 SectionKind Kind = computeSectionKind(Flags);
347 ParseSectionSwitch(SectionName, Flags, Kind);
351 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
352 StringRef SymbolName;
354 if (getParser().parseIdentifier(SymbolName))
355 return TokError("expected identifier in directive");
357 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
359 getStreamer().BeginCOFFSymbolDef(Sym);
365 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
366 int64_t SymbolStorageClass;
367 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
370 if (getLexer().isNot(AsmToken::EndOfStatement))
371 return TokError("unexpected token in directive");
374 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
378 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
380 if (getParser().parseAbsoluteExpression(Type))
383 if (getLexer().isNot(AsmToken::EndOfStatement))
384 return TokError("unexpected token in directive");
387 getStreamer().EmitCOFFSymbolType(Type);
391 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
393 getStreamer().EndCOFFSymbolDef();
397 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
399 if (getParser().parseIdentifier(SymbolID))
402 if (getLexer().isNot(AsmToken::EndOfStatement))
403 return TokError("unexpected token in directive");
405 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
408 getStreamer().EmitCOFFSecRel32(Symbol);
412 /// ParseDirectiveLinkOnce
413 /// ::= .linkonce [ identifier [ identifier ] ]
414 bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
415 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
417 if (getLexer().is(AsmToken::Identifier)) {
418 StringRef TypeId = getTok().getIdentifier();
420 Type = StringSwitch<COFF::COMDATType>(TypeId)
421 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
422 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
423 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
424 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
425 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
426 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
427 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
428 .Default((COFF::COMDATType)0);
431 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
436 const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
437 getStreamer().getCurrentSection().first);
439 const MCSectionCOFF *Assoc = 0;
440 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
442 SMLoc Loc = getTok().getLoc();
443 if (ParseSectionName(AssocName))
444 return TokError("expected associated section name");
446 Assoc = static_cast<const MCSectionCOFF*>(
447 getContext().getCOFFSection(AssocName));
449 return Error(Loc, "cannot associate unknown section '" + AssocName + "'");
450 if (Assoc == Current)
451 return Error(Loc, "cannot associate a section with itself");
452 if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT))
453 return Error(Loc, "associated section must be a COMDAT section");
454 if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
455 return Error(Loc, "associated section cannot be itself associative");
458 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
459 return Error(Loc, Twine("section '") + Current->getSectionName() +
460 "' is already linkonce");
462 Current->setSelection(Type, Assoc);
464 if (getLexer().isNot(AsmToken::EndOfStatement))
465 return TokError("unexpected token in directive");
470 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
472 if (getParser().parseIdentifier(SymbolID))
475 if (getLexer().isNot(AsmToken::EndOfStatement))
476 return TokError("unexpected token in directive");
478 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
481 getStreamer().EmitWin64EHStartProc(Symbol);
485 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
487 getStreamer().EmitWin64EHEndProc();
491 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
493 getStreamer().EmitWin64EHStartChained();
497 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
499 getStreamer().EmitWin64EHEndChained();
503 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
505 if (getParser().parseIdentifier(SymbolID))
508 if (getLexer().isNot(AsmToken::Comma))
509 return TokError("you must specify one or both of @unwind or @except");
511 bool unwind = false, except = false;
512 if (ParseAtUnwindOrAtExcept(unwind, except))
514 if (getLexer().is(AsmToken::Comma)) {
516 if (ParseAtUnwindOrAtExcept(unwind, except))
519 if (getLexer().isNot(AsmToken::EndOfStatement))
520 return TokError("unexpected token in directive");
522 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
525 getStreamer().EmitWin64EHHandler(handler, unwind, except);
529 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
531 getStreamer().EmitWin64EHHandlerData();
535 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
537 if (ParseSEHRegisterNumber(Reg))
540 if (getLexer().isNot(AsmToken::EndOfStatement))
541 return TokError("unexpected token in directive");
544 getStreamer().EmitWin64EHPushReg(Reg);
548 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
551 if (ParseSEHRegisterNumber(Reg))
553 if (getLexer().isNot(AsmToken::Comma))
554 return TokError("you must specify a stack pointer offset");
557 SMLoc startLoc = getLexer().getLoc();
558 if (getParser().parseAbsoluteExpression(Off))
562 return Error(startLoc, "offset is not a multiple of 16");
564 if (getLexer().isNot(AsmToken::EndOfStatement))
565 return TokError("unexpected token in directive");
568 getStreamer().EmitWin64EHSetFrame(Reg, Off);
572 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
574 SMLoc startLoc = getLexer().getLoc();
575 if (getParser().parseAbsoluteExpression(Size))
579 return Error(startLoc, "size is not a multiple of 8");
581 if (getLexer().isNot(AsmToken::EndOfStatement))
582 return TokError("unexpected token in directive");
585 getStreamer().EmitWin64EHAllocStack(Size);
589 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
592 if (ParseSEHRegisterNumber(Reg))
594 if (getLexer().isNot(AsmToken::Comma))
595 return TokError("you must specify an offset on the stack");
598 SMLoc startLoc = getLexer().getLoc();
599 if (getParser().parseAbsoluteExpression(Off))
603 return Error(startLoc, "size is not a multiple of 8");
605 if (getLexer().isNot(AsmToken::EndOfStatement))
606 return TokError("unexpected token in directive");
609 // FIXME: Err on %xmm* registers
610 getStreamer().EmitWin64EHSaveReg(Reg, Off);
614 // FIXME: This method is inherently x86-specific. It should really be in the
616 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
619 if (ParseSEHRegisterNumber(Reg))
621 if (getLexer().isNot(AsmToken::Comma))
622 return TokError("you must specify an offset on the stack");
625 SMLoc startLoc = getLexer().getLoc();
626 if (getParser().parseAbsoluteExpression(Off))
629 if (getLexer().isNot(AsmToken::EndOfStatement))
630 return TokError("unexpected token in directive");
633 return Error(startLoc, "offset is not a multiple of 16");
636 // FIXME: Err on non-%xmm* registers
637 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
641 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
644 if (getLexer().is(AsmToken::At)) {
645 SMLoc startLoc = getLexer().getLoc();
647 if (!getParser().parseIdentifier(CodeID)) {
648 if (CodeID != "code")
649 return Error(startLoc, "expected @code");
654 if (getLexer().isNot(AsmToken::EndOfStatement))
655 return TokError("unexpected token in directive");
658 getStreamer().EmitWin64EHPushFrame(Code);
662 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
664 getStreamer().EmitWin64EHEndProlog();
668 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
669 StringRef identifier;
670 if (getLexer().isNot(AsmToken::At))
671 return TokError("a handler attribute must begin with '@'");
672 SMLoc startLoc = getLexer().getLoc();
674 if (getParser().parseIdentifier(identifier))
675 return Error(startLoc, "expected @unwind or @except");
676 if (identifier == "unwind")
678 else if (identifier == "except")
681 return Error(startLoc, "expected @unwind or @except");
685 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
686 SMLoc startLoc = getLexer().getLoc();
687 if (getLexer().is(AsmToken::Percent)) {
688 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
691 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
695 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
696 // violation so this validation code is disabled.
698 // Check that this is a non-volatile register.
699 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
701 for (i = 0; NVRegs[i] != 0; ++i)
702 if (NVRegs[i] == LLVMRegNo)
705 return Error(startLoc, "expected non-volatile register");
708 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
710 return Error(startLoc,"register can't be represented in SEH unwind info");
715 if (getParser().parseAbsoluteExpression(n))
718 return Error(startLoc, "register number is too high");
727 MCAsmParserExtension *createCOFFAsmParser() {
728 return new COFFAsmParser;