blob: df1794c979920aa85e8218faca4f11d14c2b10a3 [file] [log] [blame]
Michael J. Spencer7d490042010-10-09 11:01:07 +00001//===- 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"
Jim Grosbachf2a35fb2011-07-25 17:55:35 +000011#include "llvm/ADT/StringSwitch.h"
Michael J. Spencer7d490042010-10-09 11:01:07 +000012#include "llvm/ADT/Twine.h"
13#include "llvm/MC/MCAsmInfo.h"
14#include "llvm/MC/MCContext.h"
Chandler Carruthd04a8d42012-12-03 16:50:05 +000015#include "llvm/MC/MCExpr.h"
Michael J. Spencer7d490042010-10-09 11:01:07 +000016#include "llvm/MC/MCParser/MCAsmLexer.h"
Evan Cheng0e6a0522011-07-18 20:57:22 +000017#include "llvm/MC/MCRegisterInfo.h"
Michael J. Spencer7d490042010-10-09 11:01:07 +000018#include "llvm/MC/MCSectionCOFF.h"
19#include "llvm/MC/MCStreamer.h"
Evan Cheng94b95502011-07-26 00:24:13 +000020#include "llvm/MC/MCTargetAsmParser.h"
Michael J. Spencer7d490042010-10-09 11:01:07 +000021#include "llvm/Support/COFF.h"
22using namespace llvm;
23
24namespace {
25
26class COFFAsmParser : public MCAsmParserExtension {
Eli Bendersky171192f2013-01-16 00:50:52 +000027 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000028 void addDirectiveHandler(StringRef Directive) {
Eli Bendersky171192f2013-01-16 00:50:52 +000029 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30 this, HandleDirective<COFFAsmParser, HandlerMethod>);
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000031 getParser().addDirectiveHandler(Directive, Handler);
Michael J. Spencer7d490042010-10-09 11:01:07 +000032 }
33
34 bool ParseSectionSwitch(StringRef Section,
35 unsigned Characteristics,
36 SectionKind Kind);
37
Nico Riecka6d343a2013-07-04 21:32:07 +000038 bool ParseSectionName(StringRef &SectionName);
39 bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
40
Michael J. Spencer7d490042010-10-09 11:01:07 +000041 virtual void Initialize(MCAsmParser &Parser) {
42 // Call the base implementation.
43 MCAsmParserExtension::Initialize(Parser);
44
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000045 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
46 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
47 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
Nico Riecka6d343a2013-07-04 21:32:07 +000048 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000049 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
50 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
51 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
52 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
53 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
Nico Rieck80646282013-07-06 12:13:10 +000054 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
Charles Davisfbc539f2011-05-22 21:12:15 +000055
56 // Win64 EH directives.
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000057 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
Charles Davisfbc539f2011-05-22 21:12:15 +000058 ".seh_proc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000059 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
Charles Davisfbc539f2011-05-22 21:12:15 +000060 ".seh_endproc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000061 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
Charles Davisfbc539f2011-05-22 21:12:15 +000062 ".seh_startchained");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000063 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
Charles Davisfbc539f2011-05-22 21:12:15 +000064 ".seh_endchained");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000065 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
Charles Davisfbc539f2011-05-22 21:12:15 +000066 ".seh_handler");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000067 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
Charles Davisfbc539f2011-05-22 21:12:15 +000068 ".seh_handlerdata");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000069 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
Charles Davisfbc539f2011-05-22 21:12:15 +000070 ".seh_pushreg");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000071 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
Charles Davisfbc539f2011-05-22 21:12:15 +000072 ".seh_setframe");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000073 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
Charles Davisfbc539f2011-05-22 21:12:15 +000074 ".seh_stackalloc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000075 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
Charles Davisfbc539f2011-05-22 21:12:15 +000076 ".seh_savereg");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000077 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
Charles Davisfbc539f2011-05-22 21:12:15 +000078 ".seh_savexmm");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000079 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
Charles Davisfbc539f2011-05-22 21:12:15 +000080 ".seh_pushframe");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000081 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
Charles Davisfbc539f2011-05-22 21:12:15 +000082 ".seh_endprologue");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000083 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
Michael J. Spencer7d490042010-10-09 11:01:07 +000084 }
85
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());
92 }
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());
99 }
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());
106 }
107
Nico Riecka6d343a2013-07-04 21:32:07 +0000108 bool ParseDirectiveSection(StringRef, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000109 bool ParseDirectiveDef(StringRef, SMLoc);
110 bool ParseDirectiveScl(StringRef, SMLoc);
111 bool ParseDirectiveType(StringRef, SMLoc);
112 bool ParseDirectiveEndef(StringRef, SMLoc);
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000113 bool ParseDirectiveSecRel32(StringRef, SMLoc);
Nico Rieck80646282013-07-06 12:13:10 +0000114 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000115
Charles Davisfbc539f2011-05-22 21:12:15 +0000116 // 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);
Charles Davis3b32d022011-05-24 20:06:30 +0000123 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);
Charles Davisfbc539f2011-05-22 21:12:15 +0000129 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
130
131 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
Charles Davis3b32d022011-05-24 20:06:30 +0000132 bool ParseSEHRegisterNumber(unsigned &RegNo);
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000133 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000134public:
135 COFFAsmParser() {}
136};
137
138} // end annonomous namespace.
139
Nico Riecka6d343a2013-07-04 21:32:07 +0000140static 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();
147}
148
149bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
150 enum {
151 None = 0,
152 Alloc = 1 << 0,
153 Code = 1 << 1,
154 Load = 1 << 2,
155 InitData = 1 << 3,
156 Shared = 1 << 4,
157 NoLoad = 1 << 5,
158 NoRead = 1 << 6,
159 NoWrite = 1 << 7
160 };
161
162 bool ReadOnlyRemoved = false;
163 unsigned SecFlags = None;
164
165 for (unsigned i = 0; i < FlagsString.size(); ++i) {
166 switch (FlagsString[i]) {
167 case 'a':
168 // Ignored.
169 break;
170
171 case 'b': // bss section
172 SecFlags |= Alloc;
173 if (SecFlags & InitData)
174 return TokError("conflicting section flags 'b' and 'd'.");
175 SecFlags &= ~Load;
176 break;
177
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)
184 SecFlags |= Load;
185 break;
186
187 case 'n': // section is not loaded
188 SecFlags |= NoLoad;
189 SecFlags &= ~Load;
190 break;
191
192 case 'r': // read-only
193 ReadOnlyRemoved = false;
194 SecFlags |= NoWrite;
195 if ((SecFlags & Code) == 0)
196 SecFlags |= InitData;
197 if ((SecFlags & NoLoad) == 0)
198 SecFlags |= Load;
199 break;
200
201 case 's': // shared section
202 SecFlags |= Shared | InitData;
203 SecFlags &= ~NoWrite;
204 if ((SecFlags & NoLoad) == 0)
205 SecFlags |= Load;
206 break;
207
208 case 'w': // writable
209 SecFlags &= ~NoWrite;
210 ReadOnlyRemoved = true;
211 break;
212
213 case 'x': // executable section
214 SecFlags |= Code;
215 if ((SecFlags & NoLoad) == 0)
216 SecFlags |= Load;
217 if (!ReadOnlyRemoved)
218 SecFlags |= NoWrite;
219 break;
220
221 case 'y': // not readable
222 SecFlags |= NoRead | NoWrite;
223 break;
224
225 default:
226 return TokError("unknown flag");
227 }
228 }
229
230 *Flags = 0;
231
232 if (SecFlags == None)
233 SecFlags = InitData;
234
235 if (SecFlags & Code)
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;
249
250 return false;
251}
252
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000253/// ParseDirectiveSymbolAttribute
254/// ::= { ".weak", ... } [ identifier ( , identifier )* ]
255bool 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)) {
261 for (;;) {
262 StringRef Name;
263
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000264 if (getParser().parseIdentifier(Name))
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000265 return TokError("expected identifier in directive");
266
267 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
268
269 getStreamer().EmitSymbolAttribute(Sym, Attr);
270
271 if (getLexer().is(AsmToken::EndOfStatement))
272 break;
273
274 if (getLexer().isNot(AsmToken::Comma))
275 return TokError("unexpected token in directive");
276 Lex();
277 }
278 }
279
280 Lex();
281 return false;
282}
283
Michael J. Spencer7d490042010-10-09 11:01:07 +0000284bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
285 unsigned Characteristics,
286 SectionKind Kind) {
287 if (getLexer().isNot(AsmToken::EndOfStatement))
288 return TokError("unexpected token in section switching directive");
289 Lex();
290
291 getStreamer().SwitchSection(getContext().getCOFFSection(
292 Section, Characteristics, Kind));
293
294 return false;
295}
296
Nico Riecka6d343a2013-07-04 21:32:07 +0000297bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
298 if (!getLexer().is(AsmToken::Identifier))
299 return true;
300
301 SectionName = getTok().getIdentifier();
302 Lex();
303 return false;
304}
305
306// .section name [, "flags"]
307//
308// Supported flags:
309// a: Ignored.
310// b: BSS section (uninitialized data)
311// d: data section (initialized data)
312// n: Discardable section
313// r: Readable section
314// s: Shared section
315// w: Writable section
316// x: Executable section
317// y: Not-readable section (clears 'r')
318//
319// Subsections are not supported.
320bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
321 StringRef SectionName;
322
323 if (ParseSectionName(SectionName))
324 return TokError("expected identifier in directive");
325
326 unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
327 COFF::IMAGE_SCN_MEM_READ |
328 COFF::IMAGE_SCN_MEM_WRITE;
329
330 if (getLexer().is(AsmToken::Comma)) {
331 Lex();
332
333 if (getLexer().isNot(AsmToken::String))
334 return TokError("expected string in directive");
335
336 StringRef FlagsStr = getTok().getStringContents();
337 Lex();
338
339 if (ParseSectionFlags(FlagsStr, &Flags))
340 return true;
341 }
342
343 if (getLexer().isNot(AsmToken::EndOfStatement))
344 return TokError("unexpected token in directive");
345
346 SectionKind Kind = computeSectionKind(Flags);
347 ParseSectionSwitch(SectionName, Flags, Kind);
348 return false;
349}
350
Michael J. Spencer7d490042010-10-09 11:01:07 +0000351bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
352 StringRef SymbolName;
353
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000354 if (getParser().parseIdentifier(SymbolName))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000355 return TokError("expected identifier in directive");
356
357 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
358
359 getStreamer().BeginCOFFSymbolDef(Sym);
360
361 Lex();
362 return false;
363}
364
365bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
366 int64_t SymbolStorageClass;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000367 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000368 return true;
369
370 if (getLexer().isNot(AsmToken::EndOfStatement))
371 return TokError("unexpected token in directive");
372
373 Lex();
374 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
375 return false;
376}
377
378bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
379 int64_t Type;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000380 if (getParser().parseAbsoluteExpression(Type))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000381 return true;
382
383 if (getLexer().isNot(AsmToken::EndOfStatement))
384 return TokError("unexpected token in directive");
385
386 Lex();
387 getStreamer().EmitCOFFSymbolType(Type);
388 return false;
389}
390
391bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
392 Lex();
393 getStreamer().EndCOFFSymbolDef();
394 return false;
395}
396
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000397bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
398 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000399 if (getParser().parseIdentifier(SymbolID))
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000400 return true;
401
402 if (getLexer().isNot(AsmToken::EndOfStatement))
403 return TokError("unexpected token in directive");
404
405 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
406
407 Lex();
408 getStreamer().EmitCOFFSecRel32(Symbol);
409 return false;
410}
411
Nico Rieck80646282013-07-06 12:13:10 +0000412/// ParseDirectiveLinkOnce
413/// ::= .linkonce [ identifier [ identifier ] ]
414bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
415 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
416
417 if (getLexer().is(AsmToken::Identifier)) {
418 StringRef TypeId = getTok().getIdentifier();
419
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);
429
430 if (Type == 0)
431 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
432
433 Lex();
434 }
435
436 const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
437 getStreamer().getCurrentSection().first);
438
439 const MCSectionCOFF *Assoc = 0;
440 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
441 StringRef AssocName;
442 SMLoc Loc = getTok().getLoc();
443 if (ParseSectionName(AssocName))
444 return TokError("expected associated section name");
445
446 Assoc = static_cast<const MCSectionCOFF*>(
447 getContext().getCOFFSection(AssocName));
448 if (!Assoc)
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");
456 }
457
458 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
459 return Error(Loc, Twine("section '") + Current->getSectionName() +
460 "' is already linkonce");
461
462 Current->setSelection(Type, Assoc);
463
464 if (getLexer().isNot(AsmToken::EndOfStatement))
465 return TokError("unexpected token in directive");
466
467 return false;
468}
469
Charles Davisfbc539f2011-05-22 21:12:15 +0000470bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000471 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000472 if (getParser().parseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000473 return true;
474
Charles Davisfbc539f2011-05-22 21:12:15 +0000475 if (getLexer().isNot(AsmToken::EndOfStatement))
476 return TokError("unexpected token in directive");
477
Charles Davis30921322011-05-25 01:33:42 +0000478 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
479
Charles Davisfbc539f2011-05-22 21:12:15 +0000480 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000481 getStreamer().EmitWin64EHStartProc(Symbol);
Charles Davisfbc539f2011-05-22 21:12:15 +0000482 return false;
483}
484
485bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
486 Lex();
487 getStreamer().EmitWin64EHEndProc();
488 return false;
489}
490
491bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
492 Lex();
493 getStreamer().EmitWin64EHStartChained();
494 return false;
495}
496
497bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
498 Lex();
499 getStreamer().EmitWin64EHEndChained();
500 return false;
501}
502
503bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000504 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000505 if (getParser().parseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000506 return true;
507
Charles Davis30921322011-05-25 01:33:42 +0000508 if (getLexer().isNot(AsmToken::Comma))
509 return TokError("you must specify one or both of @unwind or @except");
510 Lex();
Charles Davisfbc539f2011-05-22 21:12:15 +0000511 bool unwind = false, except = false;
Charles Davis30921322011-05-25 01:33:42 +0000512 if (ParseAtUnwindOrAtExcept(unwind, except))
513 return true;
Charles Davisfbc539f2011-05-22 21:12:15 +0000514 if (getLexer().is(AsmToken::Comma)) {
515 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000516 if (ParseAtUnwindOrAtExcept(unwind, except))
Charles Davisfbc539f2011-05-22 21:12:15 +0000517 return true;
518 }
519 if (getLexer().isNot(AsmToken::EndOfStatement))
520 return TokError("unexpected token in directive");
521
Charles Davis30921322011-05-25 01:33:42 +0000522 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
523
Charles Davisfbc539f2011-05-22 21:12:15 +0000524 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000525 getStreamer().EmitWin64EHHandler(handler, unwind, except);
Charles Davisfbc539f2011-05-22 21:12:15 +0000526 return false;
527}
528
529bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
530 Lex();
531 getStreamer().EmitWin64EHHandlerData();
532 return false;
533}
534
535bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000536 unsigned Reg;
537 if (ParseSEHRegisterNumber(Reg))
538 return true;
539
540 if (getLexer().isNot(AsmToken::EndOfStatement))
541 return TokError("unexpected token in directive");
542
543 Lex();
544 getStreamer().EmitWin64EHPushReg(Reg);
545 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000546}
547
548bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000549 unsigned Reg;
550 int64_t Off;
551 if (ParseSEHRegisterNumber(Reg))
552 return true;
Charles Davis410ef2b2011-05-25 21:43:45 +0000553 if (getLexer().isNot(AsmToken::Comma))
554 return TokError("you must specify a stack pointer offset");
555
556 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000557 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000558 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000559 return true;
560
561 if (Off & 0x0F)
562 return Error(startLoc, "offset is not a multiple of 16");
563
564 if (getLexer().isNot(AsmToken::EndOfStatement))
565 return TokError("unexpected token in directive");
566
567 Lex();
568 getStreamer().EmitWin64EHSetFrame(Reg, Off);
569 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000570}
571
Charles Davis16e1b3f2011-05-23 16:43:09 +0000572bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
573 int64_t Size;
Charles Davis3b32d022011-05-24 20:06:30 +0000574 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000575 if (getParser().parseAbsoluteExpression(Size))
Charles Davis16e1b3f2011-05-23 16:43:09 +0000576 return true;
577
Charles Davis3b32d022011-05-24 20:06:30 +0000578 if (Size & 7)
579 return Error(startLoc, "size is not a multiple of 8");
580
Charles Davis16e1b3f2011-05-23 16:43:09 +0000581 if (getLexer().isNot(AsmToken::EndOfStatement))
582 return TokError("unexpected token in directive");
583
584 Lex();
585 getStreamer().EmitWin64EHAllocStack(Size);
586 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000587}
588
589bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000590 unsigned Reg;
591 int64_t Off;
592 if (ParseSEHRegisterNumber(Reg))
593 return true;
Charles Davis575630c2011-05-25 04:51:25 +0000594 if (getLexer().isNot(AsmToken::Comma))
Charles Davis410ef2b2011-05-25 21:43:45 +0000595 return TokError("you must specify an offset on the stack");
Charles Davis575630c2011-05-25 04:51:25 +0000596
597 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000598 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000599 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000600 return true;
601
602 if (Off & 7)
603 return Error(startLoc, "size is not a multiple of 8");
604
605 if (getLexer().isNot(AsmToken::EndOfStatement))
606 return TokError("unexpected token in directive");
607
608 Lex();
609 // FIXME: Err on %xmm* registers
610 getStreamer().EmitWin64EHSaveReg(Reg, Off);
611 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000612}
613
Charles Davis3b32d022011-05-24 20:06:30 +0000614// FIXME: This method is inherently x86-specific. It should really be in the
615// x86 backend.
Charles Davisfbc539f2011-05-22 21:12:15 +0000616bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000617 unsigned Reg;
618 int64_t Off;
619 if (ParseSEHRegisterNumber(Reg))
620 return true;
Charles Davis575630c2011-05-25 04:51:25 +0000621 if (getLexer().isNot(AsmToken::Comma))
Charles Davis410ef2b2011-05-25 21:43:45 +0000622 return TokError("you must specify an offset on the stack");
Charles Davis575630c2011-05-25 04:51:25 +0000623
624 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000625 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000626 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000627 return true;
628
629 if (getLexer().isNot(AsmToken::EndOfStatement))
630 return TokError("unexpected token in directive");
631
632 if (Off & 0x0F)
633 return Error(startLoc, "offset is not a multiple of 16");
634
635 Lex();
636 // FIXME: Err on non-%xmm* registers
637 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
638 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000639}
640
Charles Davis16e1b3f2011-05-23 16:43:09 +0000641bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
Charles Davis47268162011-05-25 04:08:15 +0000642 bool Code = false;
Charles Davis16e1b3f2011-05-23 16:43:09 +0000643 StringRef CodeID;
Charles Davis47268162011-05-25 04:08:15 +0000644 if (getLexer().is(AsmToken::At)) {
645 SMLoc startLoc = getLexer().getLoc();
646 Lex();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000647 if (!getParser().parseIdentifier(CodeID)) {
Charles Davis47268162011-05-25 04:08:15 +0000648 if (CodeID != "code")
649 return Error(startLoc, "expected @code");
650 Code = true;
651 }
Charles Davis16e1b3f2011-05-23 16:43:09 +0000652 }
653
654 if (getLexer().isNot(AsmToken::EndOfStatement))
655 return TokError("unexpected token in directive");
656
657 Lex();
658 getStreamer().EmitWin64EHPushFrame(Code);
659 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000660}
661
662bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
663 Lex();
664 getStreamer().EmitWin64EHEndProlog();
665 return false;
666}
667
668bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
669 StringRef identifier;
Charles Davis30921322011-05-25 01:33:42 +0000670 if (getLexer().isNot(AsmToken::At))
671 return TokError("a handler attribute must begin with '@'");
Charles Davisfbc539f2011-05-22 21:12:15 +0000672 SMLoc startLoc = getLexer().getLoc();
Charles Davis30921322011-05-25 01:33:42 +0000673 Lex();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000674 if (getParser().parseIdentifier(identifier))
Charles Davisfbc539f2011-05-22 21:12:15 +0000675 return Error(startLoc, "expected @unwind or @except");
Charles Davis30921322011-05-25 01:33:42 +0000676 if (identifier == "unwind")
Charles Davisfbc539f2011-05-22 21:12:15 +0000677 unwind = true;
Charles Davis30921322011-05-25 01:33:42 +0000678 else if (identifier == "except")
Charles Davisfbc539f2011-05-22 21:12:15 +0000679 except = true;
680 else
681 return Error(startLoc, "expected @unwind or @except");
682 return false;
683}
684
Charles Davis3b32d022011-05-24 20:06:30 +0000685bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
Charles Davis3b32d022011-05-24 20:06:30 +0000686 SMLoc startLoc = getLexer().getLoc();
Charles Davis575630c2011-05-25 04:51:25 +0000687 if (getLexer().is(AsmToken::Percent)) {
Bill Wendling99cb6222013-06-18 07:20:20 +0000688 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
Charles Davis3b32d022011-05-24 20:06:30 +0000689 SMLoc endLoc;
690 unsigned LLVMRegNo;
691 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
Charles Davis575630c2011-05-25 04:51:25 +0000692 return true;
Charles Davis3b32d022011-05-24 20:06:30 +0000693
Evan Cheng0e6a0522011-07-18 20:57:22 +0000694#if 0
695 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
696 // violation so this validation code is disabled.
697
Charles Davis3b32d022011-05-24 20:06:30 +0000698 // Check that this is a non-volatile register.
Evan Cheng1be0e272011-07-15 02:09:41 +0000699 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
Charles Davis3b32d022011-05-24 20:06:30 +0000700 unsigned i;
701 for (i = 0; NVRegs[i] != 0; ++i)
702 if (NVRegs[i] == LLVMRegNo)
703 break;
704 if (NVRegs[i] == 0)
705 return Error(startLoc, "expected non-volatile register");
Evan Cheng0e6a0522011-07-18 20:57:22 +0000706#endif
Charles Davis3b32d022011-05-24 20:06:30 +0000707
Bill Wendling99cb6222013-06-18 07:20:20 +0000708 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
Charles Davis3b32d022011-05-24 20:06:30 +0000709 if (SEHRegNo < 0)
710 return Error(startLoc,"register can't be represented in SEH unwind info");
711 RegNo = SEHRegNo;
712 }
Charles Davis575630c2011-05-25 04:51:25 +0000713 else {
714 int64_t n;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000715 if (getParser().parseAbsoluteExpression(n))
Charles Davis575630c2011-05-25 04:51:25 +0000716 return true;
717 if (n > 15)
718 return Error(startLoc, "register number is too high");
Charles Davis3b32d022011-05-24 20:06:30 +0000719 RegNo = n;
Charles Davis575630c2011-05-25 04:51:25 +0000720 }
Charles Davis3b32d022011-05-24 20:06:30 +0000721
Charles Davis3b32d022011-05-24 20:06:30 +0000722 return false;
723}
724
Michael J. Spencer7d490042010-10-09 11:01:07 +0000725namespace llvm {
726
727MCAsmParserExtension *createCOFFAsmParser() {
728 return new COFFAsmParser;
729}
730
731}