blob: d8343a3eea1b67a6368e7311d829692185beb608 [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
Bill Wendling0ae07092013-11-27 06:44:18 +000038 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
39 SectionKind Kind, StringRef COMDATSymName,
40 COFF::COMDATType Type, const MCSectionCOFF *Assoc);
41
Nico Riecka6d343a2013-07-04 21:32:07 +000042 bool ParseSectionName(StringRef &SectionName);
43 bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
44
Michael J. Spencer7d490042010-10-09 11:01:07 +000045 virtual void Initialize(MCAsmParser &Parser) {
46 // Call the base implementation.
47 MCAsmParserExtension::Initialize(Parser);
48
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000049 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
50 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
51 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
Nico Riecka6d343a2013-07-04 21:32:07 +000052 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000053 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
54 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
55 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
56 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
57 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
Nico Rieck80646282013-07-06 12:13:10 +000058 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
Charles Davisfbc539f2011-05-22 21:12:15 +000059
60 // Win64 EH directives.
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000061 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
Charles Davisfbc539f2011-05-22 21:12:15 +000062 ".seh_proc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000063 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
Charles Davisfbc539f2011-05-22 21:12:15 +000064 ".seh_endproc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000065 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
Charles Davisfbc539f2011-05-22 21:12:15 +000066 ".seh_startchained");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000067 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
Charles Davisfbc539f2011-05-22 21:12:15 +000068 ".seh_endchained");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000069 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
Charles Davisfbc539f2011-05-22 21:12:15 +000070 ".seh_handler");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000071 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
Charles Davisfbc539f2011-05-22 21:12:15 +000072 ".seh_handlerdata");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000073 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
Charles Davisfbc539f2011-05-22 21:12:15 +000074 ".seh_pushreg");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000075 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
Charles Davisfbc539f2011-05-22 21:12:15 +000076 ".seh_setframe");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000077 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
Charles Davisfbc539f2011-05-22 21:12:15 +000078 ".seh_stackalloc");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000079 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
Charles Davisfbc539f2011-05-22 21:12:15 +000080 ".seh_savereg");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000081 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
Charles Davisfbc539f2011-05-22 21:12:15 +000082 ".seh_savexmm");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000083 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
Charles Davisfbc539f2011-05-22 21:12:15 +000084 ".seh_pushframe");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000085 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
Charles Davisfbc539f2011-05-22 21:12:15 +000086 ".seh_endprologue");
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +000087 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
Michael J. Spencer7d490042010-10-09 11:01:07 +000088 }
89
90 bool ParseSectionDirectiveText(StringRef, SMLoc) {
91 return ParseSectionSwitch(".text",
92 COFF::IMAGE_SCN_CNT_CODE
93 | COFF::IMAGE_SCN_MEM_EXECUTE
94 | COFF::IMAGE_SCN_MEM_READ,
95 SectionKind::getText());
96 }
97 bool ParseSectionDirectiveData(StringRef, SMLoc) {
98 return ParseSectionSwitch(".data",
99 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
100 | COFF::IMAGE_SCN_MEM_READ
101 | COFF::IMAGE_SCN_MEM_WRITE,
102 SectionKind::getDataRel());
103 }
104 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
105 return ParseSectionSwitch(".bss",
106 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
107 | COFF::IMAGE_SCN_MEM_READ
108 | COFF::IMAGE_SCN_MEM_WRITE,
109 SectionKind::getBSS());
110 }
111
Nico Riecka6d343a2013-07-04 21:32:07 +0000112 bool ParseDirectiveSection(StringRef, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000113 bool ParseDirectiveDef(StringRef, SMLoc);
114 bool ParseDirectiveScl(StringRef, SMLoc);
115 bool ParseDirectiveType(StringRef, SMLoc);
116 bool ParseDirectiveEndef(StringRef, SMLoc);
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000117 bool ParseDirectiveSecRel32(StringRef, SMLoc);
Bill Wendling0ae07092013-11-27 06:44:18 +0000118 bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
119 const MCSectionCOFF *&Assoc);
Nico Rieck80646282013-07-06 12:13:10 +0000120 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000121
Charles Davisfbc539f2011-05-22 21:12:15 +0000122 // Win64 EH directives.
123 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
124 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
125 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
126 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
127 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
128 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
Charles Davis3b32d022011-05-24 20:06:30 +0000129 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
130 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
131 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
132 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
133 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
134 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
Charles Davisfbc539f2011-05-22 21:12:15 +0000135 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
136
137 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
Charles Davis3b32d022011-05-24 20:06:30 +0000138 bool ParseSEHRegisterNumber(unsigned &RegNo);
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000139 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
Michael J. Spencer7d490042010-10-09 11:01:07 +0000140public:
141 COFFAsmParser() {}
142};
143
144} // end annonomous namespace.
145
Nico Riecka6d343a2013-07-04 21:32:07 +0000146static SectionKind computeSectionKind(unsigned Flags) {
147 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
148 return SectionKind::getText();
149 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
150 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
151 return SectionKind::getReadOnly();
152 return SectionKind::getDataRel();
153}
154
155bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
156 enum {
157 None = 0,
158 Alloc = 1 << 0,
159 Code = 1 << 1,
160 Load = 1 << 2,
161 InitData = 1 << 3,
162 Shared = 1 << 4,
163 NoLoad = 1 << 5,
164 NoRead = 1 << 6,
165 NoWrite = 1 << 7
166 };
167
168 bool ReadOnlyRemoved = false;
169 unsigned SecFlags = None;
170
171 for (unsigned i = 0; i < FlagsString.size(); ++i) {
172 switch (FlagsString[i]) {
173 case 'a':
174 // Ignored.
175 break;
176
177 case 'b': // bss section
178 SecFlags |= Alloc;
179 if (SecFlags & InitData)
180 return TokError("conflicting section flags 'b' and 'd'.");
181 SecFlags &= ~Load;
182 break;
183
184 case 'd': // data section
185 SecFlags |= InitData;
186 if (SecFlags & Alloc)
187 return TokError("conflicting section flags 'b' and 'd'.");
188 SecFlags &= ~NoWrite;
189 if ((SecFlags & NoLoad) == 0)
190 SecFlags |= Load;
191 break;
192
193 case 'n': // section is not loaded
194 SecFlags |= NoLoad;
195 SecFlags &= ~Load;
196 break;
197
198 case 'r': // read-only
199 ReadOnlyRemoved = false;
200 SecFlags |= NoWrite;
201 if ((SecFlags & Code) == 0)
202 SecFlags |= InitData;
203 if ((SecFlags & NoLoad) == 0)
204 SecFlags |= Load;
205 break;
206
207 case 's': // shared section
208 SecFlags |= Shared | InitData;
209 SecFlags &= ~NoWrite;
210 if ((SecFlags & NoLoad) == 0)
211 SecFlags |= Load;
212 break;
213
214 case 'w': // writable
215 SecFlags &= ~NoWrite;
216 ReadOnlyRemoved = true;
217 break;
218
219 case 'x': // executable section
220 SecFlags |= Code;
221 if ((SecFlags & NoLoad) == 0)
222 SecFlags |= Load;
223 if (!ReadOnlyRemoved)
224 SecFlags |= NoWrite;
225 break;
226
227 case 'y': // not readable
228 SecFlags |= NoRead | NoWrite;
229 break;
230
231 default:
232 return TokError("unknown flag");
233 }
234 }
235
236 *Flags = 0;
237
238 if (SecFlags == None)
239 SecFlags = InitData;
240
241 if (SecFlags & Code)
242 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
243 if (SecFlags & InitData)
244 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
245 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
246 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
247 if (SecFlags & NoLoad)
248 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
249 if ((SecFlags & NoRead) == 0)
250 *Flags |= COFF::IMAGE_SCN_MEM_READ;
251 if ((SecFlags & NoWrite) == 0)
252 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
253 if (SecFlags & Shared)
254 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
255
256 return false;
257}
258
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000259/// ParseDirectiveSymbolAttribute
260/// ::= { ".weak", ... } [ identifier ( , identifier )* ]
261bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
262 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
263 .Case(".weak", MCSA_Weak)
264 .Default(MCSA_Invalid);
265 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
266 if (getLexer().isNot(AsmToken::EndOfStatement)) {
267 for (;;) {
268 StringRef Name;
269
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000270 if (getParser().parseIdentifier(Name))
Jim Grosbachf2a35fb2011-07-25 17:55:35 +0000271 return TokError("expected identifier in directive");
272
273 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
274
275 getStreamer().EmitSymbolAttribute(Sym, Attr);
276
277 if (getLexer().is(AsmToken::EndOfStatement))
278 break;
279
280 if (getLexer().isNot(AsmToken::Comma))
281 return TokError("unexpected token in directive");
282 Lex();
283 }
284 }
285
286 Lex();
287 return false;
288}
289
Michael J. Spencer7d490042010-10-09 11:01:07 +0000290bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
291 unsigned Characteristics,
292 SectionKind Kind) {
Bill Wendling0ae07092013-11-27 06:44:18 +0000293 return ParseSectionSwitch(Section, Characteristics, Kind, "",
294 COFF::IMAGE_COMDAT_SELECT_ANY, 0);
295}
296
297bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
298 unsigned Characteristics,
299 SectionKind Kind,
300 StringRef COMDATSymName,
301 COFF::COMDATType Type,
302 const MCSectionCOFF *Assoc) {
Michael J. Spencer7d490042010-10-09 11:01:07 +0000303 if (getLexer().isNot(AsmToken::EndOfStatement))
304 return TokError("unexpected token in section switching directive");
305 Lex();
306
307 getStreamer().SwitchSection(getContext().getCOFFSection(
Bill Wendling0ae07092013-11-27 06:44:18 +0000308 Section, Characteristics, Kind, COMDATSymName, Type, Assoc));
Michael J. Spencer7d490042010-10-09 11:01:07 +0000309
310 return false;
311}
312
Nico Riecka6d343a2013-07-04 21:32:07 +0000313bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
Hans Wennborgab887bf2013-10-18 02:14:40 +0000314 if (!getLexer().is(AsmToken::Identifier))
315 return true;
316
317 SectionName = getTok().getIdentifier();
318 Lex();
319 return false;
Nico Riecka6d343a2013-07-04 21:32:07 +0000320}
321
Bill Wendling0ae07092013-11-27 06:44:18 +0000322// .section name [, "flags"] [, identifier [ identifier ], identifier]
Nico Riecka6d343a2013-07-04 21:32:07 +0000323//
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.
336bool 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
Bill Wendling0ae07092013-11-27 06:44:18 +0000359 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
360 const MCSectionCOFF *Assoc = 0;
361 StringRef COMDATSymName;
362 if (getLexer().is(AsmToken::Comma)) {
363 Lex();
364
365 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
366
367 if (parseCOMDATTypeAndAssoc(Type, Assoc))
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
Nico Riecka6d343a2013-07-04 21:32:07 +0000378 if (getLexer().isNot(AsmToken::EndOfStatement))
379 return TokError("unexpected token in directive");
380
381 SectionKind Kind = computeSectionKind(Flags);
Bill Wendling0ae07092013-11-27 06:44:18 +0000382 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc);
Nico Riecka6d343a2013-07-04 21:32:07 +0000383 return false;
384}
385
Michael J. Spencer7d490042010-10-09 11:01:07 +0000386bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
387 StringRef SymbolName;
388
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000389 if (getParser().parseIdentifier(SymbolName))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000390 return TokError("expected identifier in directive");
391
392 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
393
394 getStreamer().BeginCOFFSymbolDef(Sym);
395
396 Lex();
397 return false;
398}
399
400bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
401 int64_t SymbolStorageClass;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000402 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000403 return true;
404
405 if (getLexer().isNot(AsmToken::EndOfStatement))
406 return TokError("unexpected token in directive");
407
408 Lex();
409 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
410 return false;
411}
412
413bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
414 int64_t Type;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000415 if (getParser().parseAbsoluteExpression(Type))
Michael J. Spencer7d490042010-10-09 11:01:07 +0000416 return true;
417
418 if (getLexer().isNot(AsmToken::EndOfStatement))
419 return TokError("unexpected token in directive");
420
421 Lex();
422 getStreamer().EmitCOFFSymbolType(Type);
423 return false;
424}
425
426bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
427 Lex();
428 getStreamer().EndCOFFSymbolDef();
429 return false;
430}
431
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000432bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
433 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000434 if (getParser().parseIdentifier(SymbolID))
Rafael Espindola8f7d12c2011-12-17 01:14:52 +0000435 return true;
436
437 if (getLexer().isNot(AsmToken::EndOfStatement))
438 return TokError("unexpected token in directive");
439
440 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
441
442 Lex();
443 getStreamer().EmitCOFFSecRel32(Symbol);
444 return false;
445}
446
Bill Wendling0ae07092013-11-27 06:44:18 +0000447/// ::= [ identifier [ identifier ] ]
448bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type,
449 const MCSectionCOFF *&Assoc) {
450 StringRef TypeId = getTok().getIdentifier();
Nico Rieck80646282013-07-06 12:13:10 +0000451
Bill Wendling0ae07092013-11-27 06:44:18 +0000452 Type = StringSwitch<COFF::COMDATType>(TypeId)
453 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
454 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
455 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
456 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
457 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
458 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
459 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
460 .Default((COFF::COMDATType)0);
Nico Rieck80646282013-07-06 12:13:10 +0000461
Bill Wendling0ae07092013-11-27 06:44:18 +0000462 if (Type == 0)
463 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
Nico Rieck80646282013-07-06 12:13:10 +0000464
Bill Wendling0ae07092013-11-27 06:44:18 +0000465 Lex();
Nico Rieck80646282013-07-06 12:13:10 +0000466
Nico Rieck80646282013-07-06 12:13:10 +0000467 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
Nico Rieck80646282013-07-06 12:13:10 +0000468 SMLoc Loc = getTok().getLoc();
Bill Wendling0ae07092013-11-27 06:44:18 +0000469 StringRef AssocName;
Nico Rieck80646282013-07-06 12:13:10 +0000470 if (ParseSectionName(AssocName))
471 return TokError("expected associated section name");
472
473 Assoc = static_cast<const MCSectionCOFF*>(
474 getContext().getCOFFSection(AssocName));
475 if (!Assoc)
476 return Error(Loc, "cannot associate unknown section '" + AssocName + "'");
Nico Rieck80646282013-07-06 12:13:10 +0000477 if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT))
478 return Error(Loc, "associated section must be a COMDAT section");
479 if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
480 return Error(Loc, "associated section cannot be itself associative");
481 }
482
Bill Wendling0ae07092013-11-27 06:44:18 +0000483 return false;
484}
485
486/// ParseDirectiveLinkOnce
487/// ::= .linkonce [ identifier [ identifier ] ]
488bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
489 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
490 const MCSectionCOFF *Assoc = 0;
491 if (getLexer().is(AsmToken::Identifier))
492 if (parseCOMDATTypeAndAssoc(Type, Assoc))
493 return true;
494
495 const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
496 getStreamer().getCurrentSection().first);
497
498
499 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
500 if (Assoc == Current)
501 return Error(Loc, "cannot associate a section with itself");
502 }
503
Nico Rieck80646282013-07-06 12:13:10 +0000504 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
505 return Error(Loc, Twine("section '") + Current->getSectionName() +
506 "' is already linkonce");
507
508 Current->setSelection(Type, Assoc);
509
510 if (getLexer().isNot(AsmToken::EndOfStatement))
511 return TokError("unexpected token in directive");
512
513 return false;
514}
515
Charles Davisfbc539f2011-05-22 21:12:15 +0000516bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000517 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000518 if (getParser().parseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000519 return true;
520
Charles Davisfbc539f2011-05-22 21:12:15 +0000521 if (getLexer().isNot(AsmToken::EndOfStatement))
522 return TokError("unexpected token in directive");
523
Charles Davis30921322011-05-25 01:33:42 +0000524 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
525
Charles Davisfbc539f2011-05-22 21:12:15 +0000526 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000527 getStreamer().EmitWin64EHStartProc(Symbol);
Charles Davisfbc539f2011-05-22 21:12:15 +0000528 return false;
529}
530
531bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
532 Lex();
533 getStreamer().EmitWin64EHEndProc();
534 return false;
535}
536
537bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
538 Lex();
539 getStreamer().EmitWin64EHStartChained();
540 return false;
541}
542
543bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
544 Lex();
545 getStreamer().EmitWin64EHEndChained();
546 return false;
547}
548
549bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
Charles Davis30921322011-05-25 01:33:42 +0000550 StringRef SymbolID;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000551 if (getParser().parseIdentifier(SymbolID))
Charles Davisfbc539f2011-05-22 21:12:15 +0000552 return true;
553
Charles Davis30921322011-05-25 01:33:42 +0000554 if (getLexer().isNot(AsmToken::Comma))
555 return TokError("you must specify one or both of @unwind or @except");
556 Lex();
Charles Davisfbc539f2011-05-22 21:12:15 +0000557 bool unwind = false, except = false;
Charles Davis30921322011-05-25 01:33:42 +0000558 if (ParseAtUnwindOrAtExcept(unwind, except))
559 return true;
Charles Davisfbc539f2011-05-22 21:12:15 +0000560 if (getLexer().is(AsmToken::Comma)) {
561 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000562 if (ParseAtUnwindOrAtExcept(unwind, except))
Charles Davisfbc539f2011-05-22 21:12:15 +0000563 return true;
564 }
565 if (getLexer().isNot(AsmToken::EndOfStatement))
566 return TokError("unexpected token in directive");
567
Charles Davis30921322011-05-25 01:33:42 +0000568 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
569
Charles Davisfbc539f2011-05-22 21:12:15 +0000570 Lex();
Charles Davis30921322011-05-25 01:33:42 +0000571 getStreamer().EmitWin64EHHandler(handler, unwind, except);
Charles Davisfbc539f2011-05-22 21:12:15 +0000572 return false;
573}
574
575bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
576 Lex();
577 getStreamer().EmitWin64EHHandlerData();
578 return false;
579}
580
581bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000582 unsigned Reg;
583 if (ParseSEHRegisterNumber(Reg))
584 return true;
585
586 if (getLexer().isNot(AsmToken::EndOfStatement))
587 return TokError("unexpected token in directive");
588
589 Lex();
590 getStreamer().EmitWin64EHPushReg(Reg);
591 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000592}
593
594bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000595 unsigned Reg;
596 int64_t Off;
597 if (ParseSEHRegisterNumber(Reg))
598 return true;
Charles Davis410ef2b2011-05-25 21:43:45 +0000599 if (getLexer().isNot(AsmToken::Comma))
600 return TokError("you must specify a stack pointer offset");
601
602 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000603 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000604 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000605 return true;
606
607 if (Off & 0x0F)
608 return Error(startLoc, "offset is not a multiple of 16");
609
610 if (getLexer().isNot(AsmToken::EndOfStatement))
611 return TokError("unexpected token in directive");
612
613 Lex();
614 getStreamer().EmitWin64EHSetFrame(Reg, Off);
615 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000616}
617
Charles Davis16e1b3f2011-05-23 16:43:09 +0000618bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
619 int64_t Size;
Charles Davis3b32d022011-05-24 20:06:30 +0000620 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000621 if (getParser().parseAbsoluteExpression(Size))
Charles Davis16e1b3f2011-05-23 16:43:09 +0000622 return true;
623
Charles Davis3b32d022011-05-24 20:06:30 +0000624 if (Size & 7)
625 return Error(startLoc, "size is not a multiple of 8");
626
Charles Davis16e1b3f2011-05-23 16:43:09 +0000627 if (getLexer().isNot(AsmToken::EndOfStatement))
628 return TokError("unexpected token in directive");
629
630 Lex();
631 getStreamer().EmitWin64EHAllocStack(Size);
632 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000633}
634
635bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000636 unsigned Reg;
637 int64_t Off;
638 if (ParseSEHRegisterNumber(Reg))
639 return true;
Charles Davis575630c2011-05-25 04:51:25 +0000640 if (getLexer().isNot(AsmToken::Comma))
Charles Davis410ef2b2011-05-25 21:43:45 +0000641 return TokError("you must specify an offset on the stack");
Charles Davis575630c2011-05-25 04:51:25 +0000642
643 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000644 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000645 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000646 return true;
647
648 if (Off & 7)
649 return Error(startLoc, "size is not a multiple of 8");
650
651 if (getLexer().isNot(AsmToken::EndOfStatement))
652 return TokError("unexpected token in directive");
653
654 Lex();
655 // FIXME: Err on %xmm* registers
656 getStreamer().EmitWin64EHSaveReg(Reg, Off);
657 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000658}
659
Charles Davis3b32d022011-05-24 20:06:30 +0000660// FIXME: This method is inherently x86-specific. It should really be in the
661// x86 backend.
Charles Davisfbc539f2011-05-22 21:12:15 +0000662bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
Charles Davis3b32d022011-05-24 20:06:30 +0000663 unsigned Reg;
664 int64_t Off;
665 if (ParseSEHRegisterNumber(Reg))
666 return true;
Charles Davis575630c2011-05-25 04:51:25 +0000667 if (getLexer().isNot(AsmToken::Comma))
Charles Davis410ef2b2011-05-25 21:43:45 +0000668 return TokError("you must specify an offset on the stack");
Charles Davis575630c2011-05-25 04:51:25 +0000669
670 Lex();
Charles Davis3b32d022011-05-24 20:06:30 +0000671 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000672 if (getParser().parseAbsoluteExpression(Off))
Charles Davis3b32d022011-05-24 20:06:30 +0000673 return true;
674
675 if (getLexer().isNot(AsmToken::EndOfStatement))
676 return TokError("unexpected token in directive");
677
678 if (Off & 0x0F)
679 return Error(startLoc, "offset is not a multiple of 16");
680
681 Lex();
682 // FIXME: Err on non-%xmm* registers
683 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
684 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000685}
686
Charles Davis16e1b3f2011-05-23 16:43:09 +0000687bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
Charles Davis47268162011-05-25 04:08:15 +0000688 bool Code = false;
Charles Davis16e1b3f2011-05-23 16:43:09 +0000689 StringRef CodeID;
Charles Davis47268162011-05-25 04:08:15 +0000690 if (getLexer().is(AsmToken::At)) {
691 SMLoc startLoc = getLexer().getLoc();
692 Lex();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000693 if (!getParser().parseIdentifier(CodeID)) {
Charles Davis47268162011-05-25 04:08:15 +0000694 if (CodeID != "code")
695 return Error(startLoc, "expected @code");
696 Code = true;
697 }
Charles Davis16e1b3f2011-05-23 16:43:09 +0000698 }
699
700 if (getLexer().isNot(AsmToken::EndOfStatement))
701 return TokError("unexpected token in directive");
702
703 Lex();
704 getStreamer().EmitWin64EHPushFrame(Code);
705 return false;
Charles Davisfbc539f2011-05-22 21:12:15 +0000706}
707
708bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
709 Lex();
710 getStreamer().EmitWin64EHEndProlog();
711 return false;
712}
713
714bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
715 StringRef identifier;
Charles Davis30921322011-05-25 01:33:42 +0000716 if (getLexer().isNot(AsmToken::At))
717 return TokError("a handler attribute must begin with '@'");
Charles Davisfbc539f2011-05-22 21:12:15 +0000718 SMLoc startLoc = getLexer().getLoc();
Charles Davis30921322011-05-25 01:33:42 +0000719 Lex();
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000720 if (getParser().parseIdentifier(identifier))
Charles Davisfbc539f2011-05-22 21:12:15 +0000721 return Error(startLoc, "expected @unwind or @except");
Charles Davis30921322011-05-25 01:33:42 +0000722 if (identifier == "unwind")
Charles Davisfbc539f2011-05-22 21:12:15 +0000723 unwind = true;
Charles Davis30921322011-05-25 01:33:42 +0000724 else if (identifier == "except")
Charles Davisfbc539f2011-05-22 21:12:15 +0000725 except = true;
726 else
727 return Error(startLoc, "expected @unwind or @except");
728 return false;
729}
730
Charles Davis3b32d022011-05-24 20:06:30 +0000731bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
Charles Davis3b32d022011-05-24 20:06:30 +0000732 SMLoc startLoc = getLexer().getLoc();
Charles Davis575630c2011-05-25 04:51:25 +0000733 if (getLexer().is(AsmToken::Percent)) {
Bill Wendling99cb6222013-06-18 07:20:20 +0000734 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
Charles Davis3b32d022011-05-24 20:06:30 +0000735 SMLoc endLoc;
736 unsigned LLVMRegNo;
737 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
Charles Davis575630c2011-05-25 04:51:25 +0000738 return true;
Charles Davis3b32d022011-05-24 20:06:30 +0000739
Evan Cheng0e6a0522011-07-18 20:57:22 +0000740#if 0
741 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
742 // violation so this validation code is disabled.
743
Charles Davis3b32d022011-05-24 20:06:30 +0000744 // Check that this is a non-volatile register.
Evan Cheng1be0e272011-07-15 02:09:41 +0000745 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
Charles Davis3b32d022011-05-24 20:06:30 +0000746 unsigned i;
747 for (i = 0; NVRegs[i] != 0; ++i)
748 if (NVRegs[i] == LLVMRegNo)
749 break;
750 if (NVRegs[i] == 0)
751 return Error(startLoc, "expected non-volatile register");
Evan Cheng0e6a0522011-07-18 20:57:22 +0000752#endif
Charles Davis3b32d022011-05-24 20:06:30 +0000753
Bill Wendling99cb6222013-06-18 07:20:20 +0000754 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
Charles Davis3b32d022011-05-24 20:06:30 +0000755 if (SEHRegNo < 0)
756 return Error(startLoc,"register can't be represented in SEH unwind info");
757 RegNo = SEHRegNo;
758 }
Charles Davis575630c2011-05-25 04:51:25 +0000759 else {
760 int64_t n;
Jim Grosbachcb2ae3d2013-02-20 22:21:35 +0000761 if (getParser().parseAbsoluteExpression(n))
Charles Davis575630c2011-05-25 04:51:25 +0000762 return true;
763 if (n > 15)
764 return Error(startLoc, "register number is too high");
Charles Davis3b32d022011-05-24 20:06:30 +0000765 RegNo = n;
Charles Davis575630c2011-05-25 04:51:25 +0000766 }
Charles Davis3b32d022011-05-24 20:06:30 +0000767
Charles Davis3b32d022011-05-24 20:06:30 +0000768 return false;
769}
770
Michael J. Spencer7d490042010-10-09 11:01:07 +0000771namespace llvm {
772
773MCAsmParserExtension *createCOFFAsmParser() {
774 return new COFFAsmParser;
775}
776
777}