blob: 8e8447f7b89bc99b547bc7003621e6f022588f39 [file] [log] [blame]
Michael J. Spencerc8dbdfd2010-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 Grosbach38b1ed82011-07-25 17:55:35 +000011#include "llvm/ADT/StringSwitch.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000012#include "llvm/ADT/Twine.h"
13#include "llvm/MC/MCAsmInfo.h"
14#include "llvm/MC/MCContext.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000015#include "llvm/MC/MCExpr.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000016#include "llvm/MC/MCParser/MCAsmLexer.h"
Evan Chengd60fa58b2011-07-18 20:57:22 +000017#include "llvm/MC/MCRegisterInfo.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000018#include "llvm/MC/MCSectionCOFF.h"
19#include "llvm/MC/MCStreamer.h"
Evan Cheng11424442011-07-26 00:24:13 +000020#include "llvm/MC/MCTargetAsmParser.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000021#include "llvm/Support/COFF.h"
22using namespace llvm;
23
24namespace {
25
26class COFFAsmParser : public MCAsmParserExtension {
Eli Bendersky29b9f472013-01-16 00:50:52 +000027 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
Jim Grosbachd2037eb2013-02-20 22:21:35 +000028 void addDirectiveHandler(StringRef Directive) {
Eli Bendersky29b9f472013-01-16 00:50:52 +000029 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30 this, HandleDirective<COFFAsmParser, HandlerMethod>);
Jim Grosbachd2037eb2013-02-20 22:21:35 +000031 getParser().addDirectiveHandler(Directive, Handler);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000032 }
33
34 bool ParseSectionSwitch(StringRef Section,
35 unsigned Characteristics,
36 SectionKind Kind);
37
Rafael Espindola60ec3832013-11-19 19:52:52 +000038 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
39 SectionKind Kind, StringRef COMDATSymName,
Rafael Espindola0766ae02014-06-06 19:26:12 +000040 COFF::COMDATType Type);
Rafael Espindola60ec3832013-11-19 19:52:52 +000041
Nico Rieck1558c5a2013-07-04 21:32:07 +000042 bool ParseSectionName(StringRef &SectionName);
43 bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
44
Craig Topper59be68f2014-03-08 07:14:16 +000045 void Initialize(MCAsmParser &Parser) override {
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000046 // Call the base implementation.
47 MCAsmParserExtension::Initialize(Parser);
48
Jim Grosbachd2037eb2013-02-20 22:21:35 +000049 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
50 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
51 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
Nico Rieck1558c5a2013-07-04 21:32:07 +000052 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
Jim Grosbachd2037eb2013-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");
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +000058 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
Nico Riecka37acf72013-07-06 12:13:10 +000059 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
Charles Davisc7250fa2011-05-22 21:12:15 +000060
61 // Win64 EH directives.
Jim Grosbachd2037eb2013-02-20 22:21:35 +000062 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
Charles Davisc7250fa2011-05-22 21:12:15 +000063 ".seh_proc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000064 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
Charles Davisc7250fa2011-05-22 21:12:15 +000065 ".seh_endproc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000066 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
Charles Davisc7250fa2011-05-22 21:12:15 +000067 ".seh_startchained");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000068 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
Charles Davisc7250fa2011-05-22 21:12:15 +000069 ".seh_endchained");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000070 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
Charles Davisc7250fa2011-05-22 21:12:15 +000071 ".seh_handler");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000072 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
Charles Davisc7250fa2011-05-22 21:12:15 +000073 ".seh_handlerdata");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000074 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
Charles Davisc7250fa2011-05-22 21:12:15 +000075 ".seh_pushreg");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000076 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
Charles Davisc7250fa2011-05-22 21:12:15 +000077 ".seh_setframe");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000078 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
Charles Davisc7250fa2011-05-22 21:12:15 +000079 ".seh_stackalloc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000080 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
Charles Davisc7250fa2011-05-22 21:12:15 +000081 ".seh_savereg");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000082 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
Charles Davisc7250fa2011-05-22 21:12:15 +000083 ".seh_savexmm");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000084 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
Charles Davisc7250fa2011-05-22 21:12:15 +000085 ".seh_pushframe");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000086 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
Charles Davisc7250fa2011-05-22 21:12:15 +000087 ".seh_endprologue");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000088 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000089 }
90
91 bool ParseSectionDirectiveText(StringRef, SMLoc) {
92 return ParseSectionSwitch(".text",
93 COFF::IMAGE_SCN_CNT_CODE
94 | COFF::IMAGE_SCN_MEM_EXECUTE
95 | COFF::IMAGE_SCN_MEM_READ,
96 SectionKind::getText());
97 }
98 bool ParseSectionDirectiveData(StringRef, SMLoc) {
99 return ParseSectionSwitch(".data",
100 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
101 | COFF::IMAGE_SCN_MEM_READ
102 | COFF::IMAGE_SCN_MEM_WRITE,
103 SectionKind::getDataRel());
104 }
105 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
106 return ParseSectionSwitch(".bss",
107 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
108 | COFF::IMAGE_SCN_MEM_READ
109 | COFF::IMAGE_SCN_MEM_WRITE,
110 SectionKind::getBSS());
111 }
112
Nico Rieck1558c5a2013-07-04 21:32:07 +0000113 bool ParseDirectiveSection(StringRef, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000114 bool ParseDirectiveDef(StringRef, SMLoc);
115 bool ParseDirectiveScl(StringRef, SMLoc);
116 bool ParseDirectiveType(StringRef, SMLoc);
117 bool ParseDirectiveEndef(StringRef, SMLoc);
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000118 bool ParseDirectiveSecRel32(StringRef, SMLoc);
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000119 bool ParseDirectiveSecIdx(StringRef, SMLoc);
Rafael Espindola0766ae02014-06-06 19:26:12 +0000120 bool parseCOMDATType(COFF::COMDATType &Type);
Nico Riecka37acf72013-07-06 12:13:10 +0000121 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000122
Charles Davisc7250fa2011-05-22 21:12:15 +0000123 // Win64 EH directives.
124 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
125 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
126 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
127 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
128 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
129 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
Charles Davis7f6176c2011-05-24 20:06:30 +0000130 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
131 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
132 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
133 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
134 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
135 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
Charles Davisc7250fa2011-05-22 21:12:15 +0000136 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
137
138 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
Charles Davis7f6176c2011-05-24 20:06:30 +0000139 bool ParseSEHRegisterNumber(unsigned &RegNo);
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000140 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000141public:
142 COFFAsmParser() {}
143};
144
145} // end annonomous namespace.
146
Nico Rieck1558c5a2013-07-04 21:32:07 +0000147static SectionKind computeSectionKind(unsigned Flags) {
148 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
149 return SectionKind::getText();
150 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
151 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
152 return SectionKind::getReadOnly();
153 return SectionKind::getDataRel();
154}
155
156bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
157 enum {
158 None = 0,
159 Alloc = 1 << 0,
160 Code = 1 << 1,
161 Load = 1 << 2,
162 InitData = 1 << 3,
163 Shared = 1 << 4,
164 NoLoad = 1 << 5,
165 NoRead = 1 << 6,
166 NoWrite = 1 << 7
167 };
168
169 bool ReadOnlyRemoved = false;
170 unsigned SecFlags = None;
171
172 for (unsigned i = 0; i < FlagsString.size(); ++i) {
173 switch (FlagsString[i]) {
174 case 'a':
175 // Ignored.
176 break;
177
178 case 'b': // bss section
179 SecFlags |= Alloc;
180 if (SecFlags & InitData)
181 return TokError("conflicting section flags 'b' and 'd'.");
182 SecFlags &= ~Load;
183 break;
184
185 case 'd': // data section
186 SecFlags |= InitData;
187 if (SecFlags & Alloc)
188 return TokError("conflicting section flags 'b' and 'd'.");
189 SecFlags &= ~NoWrite;
190 if ((SecFlags & NoLoad) == 0)
191 SecFlags |= Load;
192 break;
193
194 case 'n': // section is not loaded
195 SecFlags |= NoLoad;
196 SecFlags &= ~Load;
197 break;
198
199 case 'r': // read-only
200 ReadOnlyRemoved = false;
201 SecFlags |= NoWrite;
202 if ((SecFlags & Code) == 0)
203 SecFlags |= InitData;
204 if ((SecFlags & NoLoad) == 0)
205 SecFlags |= Load;
206 break;
207
208 case 's': // shared section
209 SecFlags |= Shared | InitData;
210 SecFlags &= ~NoWrite;
211 if ((SecFlags & NoLoad) == 0)
212 SecFlags |= Load;
213 break;
214
215 case 'w': // writable
216 SecFlags &= ~NoWrite;
217 ReadOnlyRemoved = true;
218 break;
219
220 case 'x': // executable section
221 SecFlags |= Code;
222 if ((SecFlags & NoLoad) == 0)
223 SecFlags |= Load;
224 if (!ReadOnlyRemoved)
225 SecFlags |= NoWrite;
226 break;
227
228 case 'y': // not readable
229 SecFlags |= NoRead | NoWrite;
230 break;
231
232 default:
233 return TokError("unknown flag");
234 }
235 }
236
237 *Flags = 0;
238
239 if (SecFlags == None)
240 SecFlags = InitData;
241
242 if (SecFlags & Code)
243 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
244 if (SecFlags & InitData)
245 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
246 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
247 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
248 if (SecFlags & NoLoad)
249 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
250 if ((SecFlags & NoRead) == 0)
251 *Flags |= COFF::IMAGE_SCN_MEM_READ;
252 if ((SecFlags & NoWrite) == 0)
253 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
254 if (SecFlags & Shared)
255 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
256
257 return false;
258}
259
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000260/// ParseDirectiveSymbolAttribute
261/// ::= { ".weak", ... } [ identifier ( , identifier )* ]
262bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
263 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
264 .Case(".weak", MCSA_Weak)
265 .Default(MCSA_Invalid);
266 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
267 if (getLexer().isNot(AsmToken::EndOfStatement)) {
268 for (;;) {
269 StringRef Name;
270
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000271 if (getParser().parseIdentifier(Name))
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000272 return TokError("expected identifier in directive");
273
274 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
275
276 getStreamer().EmitSymbolAttribute(Sym, Attr);
277
278 if (getLexer().is(AsmToken::EndOfStatement))
279 break;
280
281 if (getLexer().isNot(AsmToken::Comma))
282 return TokError("unexpected token in directive");
283 Lex();
284 }
285 }
286
287 Lex();
288 return false;
289}
290
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000291bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
292 unsigned Characteristics,
293 SectionKind Kind) {
Rafael Espindola60ec3832013-11-19 19:52:52 +0000294 return ParseSectionSwitch(Section, Characteristics, Kind, "",
Rafael Espindola0766ae02014-06-06 19:26:12 +0000295 COFF::IMAGE_COMDAT_SELECT_ANY);
Rafael Espindola60ec3832013-11-19 19:52:52 +0000296}
297
298bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
299 unsigned Characteristics,
300 SectionKind Kind,
301 StringRef COMDATSymName,
Rafael Espindola0766ae02014-06-06 19:26:12 +0000302 COFF::COMDATType Type) {
Michael J. Spencerc8dbdfd2010-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(
Rafael Espindola0766ae02014-06-06 19:26:12 +0000308 Section, Characteristics, Kind, COMDATSymName, Type));
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000309
310 return false;
311}
312
Nico Rieck1558c5a2013-07-04 21:32:07 +0000313bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
Hans Wennborg7ddcdc82013-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 Rieck1558c5a2013-07-04 21:32:07 +0000320}
321
Rafael Espindola60ec3832013-11-19 19:52:52 +0000322// .section name [, "flags"] [, identifier [ identifier ], identifier]
Nico Rieck1558c5a2013-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
Rafael Espindola60ec3832013-11-19 19:52:52 +0000359 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
Rafael Espindola60ec3832013-11-19 19:52:52 +0000360 StringRef COMDATSymName;
361 if (getLexer().is(AsmToken::Comma)) {
362 Lex();
363
364 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
365
Rafael Espindola0766ae02014-06-06 19:26:12 +0000366 if (parseCOMDATType(Type))
Rafael Espindola60ec3832013-11-19 19:52:52 +0000367 return true;
368
369 if (getLexer().isNot(AsmToken::Comma))
370 return TokError("expected comma in directive");
371 Lex();
372
373 if (getParser().parseIdentifier(COMDATSymName))
374 return TokError("expected identifier in directive");
375 }
376
Nico Rieck1558c5a2013-07-04 21:32:07 +0000377 if (getLexer().isNot(AsmToken::EndOfStatement))
378 return TokError("unexpected token in directive");
379
380 SectionKind Kind = computeSectionKind(Flags);
Rafael Espindola0766ae02014-06-06 19:26:12 +0000381 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
Nico Rieck1558c5a2013-07-04 21:32:07 +0000382 return false;
383}
384
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000385bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
386 StringRef SymbolName;
387
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000388 if (getParser().parseIdentifier(SymbolName))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000389 return TokError("expected identifier in directive");
390
391 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
392
393 getStreamer().BeginCOFFSymbolDef(Sym);
394
395 Lex();
396 return false;
397}
398
399bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
400 int64_t SymbolStorageClass;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000401 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000402 return true;
403
404 if (getLexer().isNot(AsmToken::EndOfStatement))
405 return TokError("unexpected token in directive");
406
407 Lex();
408 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
409 return false;
410}
411
412bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
413 int64_t Type;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000414 if (getParser().parseAbsoluteExpression(Type))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000415 return true;
416
417 if (getLexer().isNot(AsmToken::EndOfStatement))
418 return TokError("unexpected token in directive");
419
420 Lex();
421 getStreamer().EmitCOFFSymbolType(Type);
422 return false;
423}
424
425bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
426 Lex();
427 getStreamer().EndCOFFSymbolDef();
428 return false;
429}
430
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000431bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
432 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000433 if (getParser().parseIdentifier(SymbolID))
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000434 return TokError("expected identifier in directive");
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000435
436 if (getLexer().isNot(AsmToken::EndOfStatement))
437 return TokError("unexpected token in directive");
438
439 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
440
441 Lex();
442 getStreamer().EmitCOFFSecRel32(Symbol);
443 return false;
444}
445
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000446bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
447 StringRef SymbolID;
448 if (getParser().parseIdentifier(SymbolID))
449 return TokError("expected identifier in directive");
450
451 if (getLexer().isNot(AsmToken::EndOfStatement))
452 return TokError("unexpected token in directive");
453
454 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
455
456 Lex();
457 getStreamer().EmitCOFFSectionIndex(Symbol);
458 return false;
459}
460
Rafael Espindola0766ae02014-06-06 19:26:12 +0000461/// ::= [ identifier ]
462bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
Rafael Espindola60ec3832013-11-19 19:52:52 +0000463 StringRef TypeId = getTok().getIdentifier();
Nico Riecka37acf72013-07-06 12:13:10 +0000464
Rafael Espindola60ec3832013-11-19 19:52:52 +0000465 Type = StringSwitch<COFF::COMDATType>(TypeId)
466 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
467 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
468 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
469 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
470 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
471 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
472 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
473 .Default((COFF::COMDATType)0);
Nico Riecka37acf72013-07-06 12:13:10 +0000474
Rafael Espindola60ec3832013-11-19 19:52:52 +0000475 if (Type == 0)
476 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
Nico Riecka37acf72013-07-06 12:13:10 +0000477
Rafael Espindola60ec3832013-11-19 19:52:52 +0000478 Lex();
Nico Riecka37acf72013-07-06 12:13:10 +0000479
Rafael Espindola60ec3832013-11-19 19:52:52 +0000480 return false;
481}
482
483/// ParseDirectiveLinkOnce
Rafael Espindola0766ae02014-06-06 19:26:12 +0000484/// ::= .linkonce [ identifier ]
Rafael Espindola60ec3832013-11-19 19:52:52 +0000485bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
486 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
Rafael Espindola60ec3832013-11-19 19:52:52 +0000487 if (getLexer().is(AsmToken::Identifier))
Rafael Espindola0766ae02014-06-06 19:26:12 +0000488 if (parseCOMDATType(Type))
Rafael Espindola60ec3832013-11-19 19:52:52 +0000489 return true;
490
491 const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
492 getStreamer().getCurrentSection().first);
493
Rafael Espindola0766ae02014-06-06 19:26:12 +0000494 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
495 return Error(Loc, "cannot make section associative with .linkonce");
Rafael Espindola60ec3832013-11-19 19:52:52 +0000496
Nico Riecka37acf72013-07-06 12:13:10 +0000497 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
498 return Error(Loc, Twine("section '") + Current->getSectionName() +
499 "' is already linkonce");
500
Rafael Espindola0766ae02014-06-06 19:26:12 +0000501 Current->setSelection(Type);
Nico Riecka37acf72013-07-06 12:13:10 +0000502
503 if (getLexer().isNot(AsmToken::EndOfStatement))
504 return TokError("unexpected token in directive");
505
506 return false;
507}
508
Charles Davisc7250fa2011-05-22 21:12:15 +0000509bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000510 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000511 if (getParser().parseIdentifier(SymbolID))
Charles Davisc7250fa2011-05-22 21:12:15 +0000512 return true;
513
Charles Davisc7250fa2011-05-22 21:12:15 +0000514 if (getLexer().isNot(AsmToken::EndOfStatement))
515 return TokError("unexpected token in directive");
516
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000517 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
518
Charles Davisc7250fa2011-05-22 21:12:15 +0000519 Lex();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000520 getStreamer().EmitWin64EHStartProc(Symbol);
Charles Davisc7250fa2011-05-22 21:12:15 +0000521 return false;
522}
523
524bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
525 Lex();
526 getStreamer().EmitWin64EHEndProc();
527 return false;
528}
529
530bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
531 Lex();
532 getStreamer().EmitWin64EHStartChained();
533 return false;
534}
535
536bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
537 Lex();
538 getStreamer().EmitWin64EHEndChained();
539 return false;
540}
541
542bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000543 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000544 if (getParser().parseIdentifier(SymbolID))
Charles Davisc7250fa2011-05-22 21:12:15 +0000545 return true;
546
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000547 if (getLexer().isNot(AsmToken::Comma))
548 return TokError("you must specify one or both of @unwind or @except");
549 Lex();
Charles Davisc7250fa2011-05-22 21:12:15 +0000550 bool unwind = false, except = false;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000551 if (ParseAtUnwindOrAtExcept(unwind, except))
552 return true;
Charles Davisc7250fa2011-05-22 21:12:15 +0000553 if (getLexer().is(AsmToken::Comma)) {
554 Lex();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000555 if (ParseAtUnwindOrAtExcept(unwind, except))
Charles Davisc7250fa2011-05-22 21:12:15 +0000556 return true;
557 }
558 if (getLexer().isNot(AsmToken::EndOfStatement))
559 return TokError("unexpected token in directive");
560
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000561 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
562
Charles Davisc7250fa2011-05-22 21:12:15 +0000563 Lex();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000564 getStreamer().EmitWin64EHHandler(handler, unwind, except);
Charles Davisc7250fa2011-05-22 21:12:15 +0000565 return false;
566}
567
568bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
569 Lex();
570 getStreamer().EmitWin64EHHandlerData();
571 return false;
572}
573
574bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000575 unsigned Reg;
576 if (ParseSEHRegisterNumber(Reg))
577 return true;
578
579 if (getLexer().isNot(AsmToken::EndOfStatement))
580 return TokError("unexpected token in directive");
581
582 Lex();
583 getStreamer().EmitWin64EHPushReg(Reg);
584 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000585}
586
587bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000588 unsigned Reg;
589 int64_t Off;
590 if (ParseSEHRegisterNumber(Reg))
591 return true;
Charles Davis2f6ecea2011-05-25 21:43:45 +0000592 if (getLexer().isNot(AsmToken::Comma))
593 return TokError("you must specify a stack pointer offset");
594
595 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000596 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000597 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000598 return true;
599
600 if (Off & 0x0F)
601 return Error(startLoc, "offset is not a multiple of 16");
602
603 if (getLexer().isNot(AsmToken::EndOfStatement))
604 return TokError("unexpected token in directive");
605
606 Lex();
607 getStreamer().EmitWin64EHSetFrame(Reg, Off);
608 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000609}
610
Charles Davisd9eafdc2011-05-23 16:43:09 +0000611bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
612 int64_t Size;
Charles Davis7f6176c2011-05-24 20:06:30 +0000613 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000614 if (getParser().parseAbsoluteExpression(Size))
Charles Davisd9eafdc2011-05-23 16:43:09 +0000615 return true;
616
Charles Davis7f6176c2011-05-24 20:06:30 +0000617 if (Size & 7)
618 return Error(startLoc, "size is not a multiple of 8");
619
Charles Davisd9eafdc2011-05-23 16:43:09 +0000620 if (getLexer().isNot(AsmToken::EndOfStatement))
621 return TokError("unexpected token in directive");
622
623 Lex();
624 getStreamer().EmitWin64EHAllocStack(Size);
625 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000626}
627
628bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000629 unsigned Reg;
630 int64_t Off;
631 if (ParseSEHRegisterNumber(Reg))
632 return true;
Charles Davis828b00c2011-05-25 04:51:25 +0000633 if (getLexer().isNot(AsmToken::Comma))
Charles Davis2f6ecea2011-05-25 21:43:45 +0000634 return TokError("you must specify an offset on the stack");
Charles Davis828b00c2011-05-25 04:51:25 +0000635
636 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000637 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000638 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000639 return true;
640
641 if (Off & 7)
642 return Error(startLoc, "size is not a multiple of 8");
643
644 if (getLexer().isNot(AsmToken::EndOfStatement))
645 return TokError("unexpected token in directive");
646
647 Lex();
648 // FIXME: Err on %xmm* registers
649 getStreamer().EmitWin64EHSaveReg(Reg, Off);
650 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000651}
652
Charles Davis7f6176c2011-05-24 20:06:30 +0000653// FIXME: This method is inherently x86-specific. It should really be in the
654// x86 backend.
Charles Davisc7250fa2011-05-22 21:12:15 +0000655bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000656 unsigned Reg;
657 int64_t Off;
658 if (ParseSEHRegisterNumber(Reg))
659 return true;
Charles Davis828b00c2011-05-25 04:51:25 +0000660 if (getLexer().isNot(AsmToken::Comma))
Charles Davis2f6ecea2011-05-25 21:43:45 +0000661 return TokError("you must specify an offset on the stack");
Charles Davis828b00c2011-05-25 04:51:25 +0000662
663 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000664 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000665 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000666 return true;
667
668 if (getLexer().isNot(AsmToken::EndOfStatement))
669 return TokError("unexpected token in directive");
670
671 if (Off & 0x0F)
672 return Error(startLoc, "offset is not a multiple of 16");
673
674 Lex();
675 // FIXME: Err on non-%xmm* registers
676 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
677 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000678}
679
Charles Davisd9eafdc2011-05-23 16:43:09 +0000680bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
Charles Davisb0c4f392011-05-25 04:08:15 +0000681 bool Code = false;
Charles Davisd9eafdc2011-05-23 16:43:09 +0000682 StringRef CodeID;
Charles Davisb0c4f392011-05-25 04:08:15 +0000683 if (getLexer().is(AsmToken::At)) {
684 SMLoc startLoc = getLexer().getLoc();
685 Lex();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000686 if (!getParser().parseIdentifier(CodeID)) {
Charles Davisb0c4f392011-05-25 04:08:15 +0000687 if (CodeID != "code")
688 return Error(startLoc, "expected @code");
689 Code = true;
690 }
Charles Davisd9eafdc2011-05-23 16:43:09 +0000691 }
692
693 if (getLexer().isNot(AsmToken::EndOfStatement))
694 return TokError("unexpected token in directive");
695
696 Lex();
697 getStreamer().EmitWin64EHPushFrame(Code);
698 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000699}
700
701bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
702 Lex();
703 getStreamer().EmitWin64EHEndProlog();
704 return false;
705}
706
707bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
708 StringRef identifier;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000709 if (getLexer().isNot(AsmToken::At))
710 return TokError("a handler attribute must begin with '@'");
Charles Davisc7250fa2011-05-22 21:12:15 +0000711 SMLoc startLoc = getLexer().getLoc();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000712 Lex();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000713 if (getParser().parseIdentifier(identifier))
Charles Davisc7250fa2011-05-22 21:12:15 +0000714 return Error(startLoc, "expected @unwind or @except");
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000715 if (identifier == "unwind")
Charles Davisc7250fa2011-05-22 21:12:15 +0000716 unwind = true;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000717 else if (identifier == "except")
Charles Davisc7250fa2011-05-22 21:12:15 +0000718 except = true;
719 else
720 return Error(startLoc, "expected @unwind or @except");
721 return false;
722}
723
Charles Davis7f6176c2011-05-24 20:06:30 +0000724bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000725 SMLoc startLoc = getLexer().getLoc();
Charles Davis828b00c2011-05-25 04:51:25 +0000726 if (getLexer().is(AsmToken::Percent)) {
Bill Wendlingbc07a892013-06-18 07:20:20 +0000727 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
Charles Davis7f6176c2011-05-24 20:06:30 +0000728 SMLoc endLoc;
729 unsigned LLVMRegNo;
730 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
Charles Davis828b00c2011-05-25 04:51:25 +0000731 return true;
Charles Davis7f6176c2011-05-24 20:06:30 +0000732
Evan Chengd60fa58b2011-07-18 20:57:22 +0000733#if 0
734 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
735 // violation so this validation code is disabled.
736
Charles Davis7f6176c2011-05-24 20:06:30 +0000737 // Check that this is a non-volatile register.
Evan Chenga83b37a2011-07-15 02:09:41 +0000738 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
Charles Davis7f6176c2011-05-24 20:06:30 +0000739 unsigned i;
740 for (i = 0; NVRegs[i] != 0; ++i)
741 if (NVRegs[i] == LLVMRegNo)
742 break;
743 if (NVRegs[i] == 0)
744 return Error(startLoc, "expected non-volatile register");
Evan Chengd60fa58b2011-07-18 20:57:22 +0000745#endif
Charles Davis7f6176c2011-05-24 20:06:30 +0000746
Bill Wendlingbc07a892013-06-18 07:20:20 +0000747 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
Charles Davis7f6176c2011-05-24 20:06:30 +0000748 if (SEHRegNo < 0)
749 return Error(startLoc,"register can't be represented in SEH unwind info");
750 RegNo = SEHRegNo;
751 }
Charles Davis828b00c2011-05-25 04:51:25 +0000752 else {
753 int64_t n;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000754 if (getParser().parseAbsoluteExpression(n))
Charles Davis828b00c2011-05-25 04:51:25 +0000755 return true;
756 if (n > 15)
757 return Error(startLoc, "register number is too high");
Charles Davis7f6176c2011-05-24 20:06:30 +0000758 RegNo = n;
Charles Davis828b00c2011-05-25 04:51:25 +0000759 }
Charles Davis7f6176c2011-05-24 20:06:30 +0000760
Charles Davis7f6176c2011-05-24 20:06:30 +0000761 return false;
762}
763
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000764namespace llvm {
765
766MCAsmParserExtension *createCOFFAsmParser() {
767 return new COFFAsmParser;
768}
769
770}