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");
55 // Win64 EH directives.
56 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
58 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
60 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
62 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
64 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
66 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
68 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
70 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
72 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
74 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
78 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
80 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
82 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
85 bool ParseSectionDirectiveText(StringRef, SMLoc) {
86 return ParseSectionSwitch(".text",
87 COFF::IMAGE_SCN_CNT_CODE
88 | COFF::IMAGE_SCN_MEM_EXECUTE
89 | COFF::IMAGE_SCN_MEM_READ,
90 SectionKind::getText());
92 bool ParseSectionDirectiveData(StringRef, SMLoc) {
93 return ParseSectionSwitch(".data",
94 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
95 | COFF::IMAGE_SCN_MEM_READ
96 | COFF::IMAGE_SCN_MEM_WRITE,
97 SectionKind::getDataRel());
99 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
100 return ParseSectionSwitch(".bss",
101 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
102 | COFF::IMAGE_SCN_MEM_READ
103 | COFF::IMAGE_SCN_MEM_WRITE,
104 SectionKind::getBSS());
107 bool ParseDirectiveSection(StringRef, SMLoc);
108 bool ParseDirectiveDef(StringRef, SMLoc);
109 bool ParseDirectiveScl(StringRef, SMLoc);
110 bool ParseDirectiveType(StringRef, SMLoc);
111 bool ParseDirectiveEndef(StringRef, SMLoc);
112 bool ParseDirectiveSecRel32(StringRef, SMLoc);
114 // Win64 EH directives.
115 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
116 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
117 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
118 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
119 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
120 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
121 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
122 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
123 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
124 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
125 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
126 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
127 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
129 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
130 bool ParseSEHRegisterNumber(unsigned &RegNo);
131 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
136 } // end annonomous namespace.
138 static SectionKind computeSectionKind(unsigned Flags) {
139 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
140 return SectionKind::getText();
141 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
142 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
143 return SectionKind::getReadOnly();
144 return SectionKind::getDataRel();
147 bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
160 bool ReadOnlyRemoved = false;
161 unsigned SecFlags = None;
163 for (unsigned i = 0; i < FlagsString.size(); ++i) {
164 switch (FlagsString[i]) {
169 case 'b': // bss section
171 if (SecFlags & InitData)
172 return TokError("conflicting section flags 'b' and 'd'.");
176 case 'd': // data section
177 SecFlags |= InitData;
178 if (SecFlags & Alloc)
179 return TokError("conflicting section flags 'b' and 'd'.");
180 SecFlags &= ~NoWrite;
181 if ((SecFlags & NoLoad) == 0)
185 case 'n': // section is not loaded
190 case 'r': // read-only
191 ReadOnlyRemoved = false;
193 if ((SecFlags & Code) == 0)
194 SecFlags |= InitData;
195 if ((SecFlags & NoLoad) == 0)
199 case 's': // shared section
200 SecFlags |= Shared | InitData;
201 SecFlags &= ~NoWrite;
202 if ((SecFlags & NoLoad) == 0)
206 case 'w': // writable
207 SecFlags &= ~NoWrite;
208 ReadOnlyRemoved = true;
211 case 'x': // executable section
213 if ((SecFlags & NoLoad) == 0)
215 if (!ReadOnlyRemoved)
219 case 'y': // not readable
220 SecFlags |= NoRead | NoWrite;
224 return TokError("unknown flag");
230 if (SecFlags == None)
234 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
235 if (SecFlags & InitData)
236 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
237 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
238 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
239 if (SecFlags & NoLoad)
240 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
241 if ((SecFlags & NoRead) == 0)
242 *Flags |= COFF::IMAGE_SCN_MEM_READ;
243 if ((SecFlags & NoWrite) == 0)
244 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
245 if (SecFlags & Shared)
246 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
251 /// ParseDirectiveSymbolAttribute
252 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
253 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
254 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
255 .Case(".weak", MCSA_Weak)
256 .Default(MCSA_Invalid);
257 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
258 if (getLexer().isNot(AsmToken::EndOfStatement)) {
262 if (getParser().parseIdentifier(Name))
263 return TokError("expected identifier in directive");
265 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
267 getStreamer().EmitSymbolAttribute(Sym, Attr);
269 if (getLexer().is(AsmToken::EndOfStatement))
272 if (getLexer().isNot(AsmToken::Comma))
273 return TokError("unexpected token in directive");
282 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
283 unsigned Characteristics,
285 if (getLexer().isNot(AsmToken::EndOfStatement))
286 return TokError("unexpected token in section switching directive");
289 getStreamer().SwitchSection(getContext().getCOFFSection(
290 Section, Characteristics, Kind));
295 bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
296 if (!getLexer().is(AsmToken::Identifier))
299 SectionName = getTok().getIdentifier();
304 // .section name [, "flags"]
308 // b: BSS section (uninitialized data)
309 // d: data section (initialized data)
310 // n: Discardable section
311 // r: Readable section
313 // w: Writable section
314 // x: Executable section
315 // y: Not-readable section (clears 'r')
317 // Subsections are not supported.
318 bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
319 StringRef SectionName;
321 if (ParseSectionName(SectionName))
322 return TokError("expected identifier in directive");
324 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
325 COFF::IMAGE_SCN_MEM_READ |
326 COFF::IMAGE_SCN_MEM_WRITE;
328 if (getLexer().is(AsmToken::Comma)) {
331 if (getLexer().isNot(AsmToken::String))
332 return TokError("expected string in directive");
334 StringRef FlagsStr = getTok().getStringContents();
337 if (ParseSectionFlags(FlagsStr, &Flags))
341 if (getLexer().isNot(AsmToken::EndOfStatement))
342 return TokError("unexpected token in directive");
344 SectionKind Kind = computeSectionKind(Flags);
345 ParseSectionSwitch(SectionName, Flags, Kind);
349 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
350 StringRef SymbolName;
352 if (getParser().parseIdentifier(SymbolName))
353 return TokError("expected identifier in directive");
355 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
357 getStreamer().BeginCOFFSymbolDef(Sym);
363 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
364 int64_t SymbolStorageClass;
365 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
368 if (getLexer().isNot(AsmToken::EndOfStatement))
369 return TokError("unexpected token in directive");
372 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
376 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
378 if (getParser().parseAbsoluteExpression(Type))
381 if (getLexer().isNot(AsmToken::EndOfStatement))
382 return TokError("unexpected token in directive");
385 getStreamer().EmitCOFFSymbolType(Type);
389 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
391 getStreamer().EndCOFFSymbolDef();
395 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
397 if (getParser().parseIdentifier(SymbolID))
400 if (getLexer().isNot(AsmToken::EndOfStatement))
401 return TokError("unexpected token in directive");
403 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
406 getStreamer().EmitCOFFSecRel32(Symbol);
410 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
412 if (getParser().parseIdentifier(SymbolID))
415 if (getLexer().isNot(AsmToken::EndOfStatement))
416 return TokError("unexpected token in directive");
418 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
421 getStreamer().EmitWin64EHStartProc(Symbol);
425 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
427 getStreamer().EmitWin64EHEndProc();
431 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
433 getStreamer().EmitWin64EHStartChained();
437 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
439 getStreamer().EmitWin64EHEndChained();
443 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
445 if (getParser().parseIdentifier(SymbolID))
448 if (getLexer().isNot(AsmToken::Comma))
449 return TokError("you must specify one or both of @unwind or @except");
451 bool unwind = false, except = false;
452 if (ParseAtUnwindOrAtExcept(unwind, except))
454 if (getLexer().is(AsmToken::Comma)) {
456 if (ParseAtUnwindOrAtExcept(unwind, except))
459 if (getLexer().isNot(AsmToken::EndOfStatement))
460 return TokError("unexpected token in directive");
462 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
465 getStreamer().EmitWin64EHHandler(handler, unwind, except);
469 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
471 getStreamer().EmitWin64EHHandlerData();
475 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
477 if (ParseSEHRegisterNumber(Reg))
480 if (getLexer().isNot(AsmToken::EndOfStatement))
481 return TokError("unexpected token in directive");
484 getStreamer().EmitWin64EHPushReg(Reg);
488 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
491 if (ParseSEHRegisterNumber(Reg))
493 if (getLexer().isNot(AsmToken::Comma))
494 return TokError("you must specify a stack pointer offset");
497 SMLoc startLoc = getLexer().getLoc();
498 if (getParser().parseAbsoluteExpression(Off))
502 return Error(startLoc, "offset is not a multiple of 16");
504 if (getLexer().isNot(AsmToken::EndOfStatement))
505 return TokError("unexpected token in directive");
508 getStreamer().EmitWin64EHSetFrame(Reg, Off);
512 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
514 SMLoc startLoc = getLexer().getLoc();
515 if (getParser().parseAbsoluteExpression(Size))
519 return Error(startLoc, "size is not a multiple of 8");
521 if (getLexer().isNot(AsmToken::EndOfStatement))
522 return TokError("unexpected token in directive");
525 getStreamer().EmitWin64EHAllocStack(Size);
529 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
532 if (ParseSEHRegisterNumber(Reg))
534 if (getLexer().isNot(AsmToken::Comma))
535 return TokError("you must specify an offset on the stack");
538 SMLoc startLoc = getLexer().getLoc();
539 if (getParser().parseAbsoluteExpression(Off))
543 return Error(startLoc, "size is not a multiple of 8");
545 if (getLexer().isNot(AsmToken::EndOfStatement))
546 return TokError("unexpected token in directive");
549 // FIXME: Err on %xmm* registers
550 getStreamer().EmitWin64EHSaveReg(Reg, Off);
554 // FIXME: This method is inherently x86-specific. It should really be in the
556 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
559 if (ParseSEHRegisterNumber(Reg))
561 if (getLexer().isNot(AsmToken::Comma))
562 return TokError("you must specify an offset on the stack");
565 SMLoc startLoc = getLexer().getLoc();
566 if (getParser().parseAbsoluteExpression(Off))
569 if (getLexer().isNot(AsmToken::EndOfStatement))
570 return TokError("unexpected token in directive");
573 return Error(startLoc, "offset is not a multiple of 16");
576 // FIXME: Err on non-%xmm* registers
577 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
581 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
584 if (getLexer().is(AsmToken::At)) {
585 SMLoc startLoc = getLexer().getLoc();
587 if (!getParser().parseIdentifier(CodeID)) {
588 if (CodeID != "code")
589 return Error(startLoc, "expected @code");
594 if (getLexer().isNot(AsmToken::EndOfStatement))
595 return TokError("unexpected token in directive");
598 getStreamer().EmitWin64EHPushFrame(Code);
602 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
604 getStreamer().EmitWin64EHEndProlog();
608 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
609 StringRef identifier;
610 if (getLexer().isNot(AsmToken::At))
611 return TokError("a handler attribute must begin with '@'");
612 SMLoc startLoc = getLexer().getLoc();
614 if (getParser().parseIdentifier(identifier))
615 return Error(startLoc, "expected @unwind or @except");
616 if (identifier == "unwind")
618 else if (identifier == "except")
621 return Error(startLoc, "expected @unwind or @except");
625 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
626 SMLoc startLoc = getLexer().getLoc();
627 if (getLexer().is(AsmToken::Percent)) {
628 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
631 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
635 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
636 // violation so this validation code is disabled.
638 // Check that this is a non-volatile register.
639 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
641 for (i = 0; NVRegs[i] != 0; ++i)
642 if (NVRegs[i] == LLVMRegNo)
645 return Error(startLoc, "expected non-volatile register");
648 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
650 return Error(startLoc,"register can't be represented in SEH unwind info");
655 if (getParser().parseAbsoluteExpression(n))
658 return Error(startLoc, "register number is too high");
667 MCAsmParserExtension *createCOFFAsmParser() {
668 return new COFFAsmParser;