blob: 18bdb03336afe2294e3144eccc4f95fdeb99bf07 [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"
Saleem Abdulrasoolbdbc0082014-06-22 22:25:01 +000016#include "llvm/MC/MCObjectFileInfo.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000017#include "llvm/MC/MCParser/MCAsmLexer.h"
Evan Chengd60fa58b2011-07-18 20:57:22 +000018#include "llvm/MC/MCRegisterInfo.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000019#include "llvm/MC/MCSectionCOFF.h"
20#include "llvm/MC/MCStreamer.h"
Evan Cheng11424442011-07-26 00:24:13 +000021#include "llvm/MC/MCTargetAsmParser.h"
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000022#include "llvm/Support/COFF.h"
23using namespace llvm;
24
25namespace {
26
27class COFFAsmParser : public MCAsmParserExtension {
Eli Bendersky29b9f472013-01-16 00:50:52 +000028 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
Jim Grosbachd2037eb2013-02-20 22:21:35 +000029 void addDirectiveHandler(StringRef Directive) {
Eli Bendersky29b9f472013-01-16 00:50:52 +000030 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
31 this, HandleDirective<COFFAsmParser, HandlerMethod>);
Jim Grosbachd2037eb2013-02-20 22:21:35 +000032 getParser().addDirectiveHandler(Directive, Handler);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000033 }
34
35 bool ParseSectionSwitch(StringRef Section,
36 unsigned Characteristics,
37 SectionKind Kind);
38
Rafael Espindola60ec3832013-11-19 19:52:52 +000039 bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
40 SectionKind Kind, StringRef COMDATSymName,
Rafael Espindola0766ae02014-06-06 19:26:12 +000041 COFF::COMDATType Type);
Rafael Espindola60ec3832013-11-19 19:52:52 +000042
Nico Rieck1558c5a2013-07-04 21:32:07 +000043 bool ParseSectionName(StringRef &SectionName);
44 bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags);
45
Craig Topper59be68f2014-03-08 07:14:16 +000046 void Initialize(MCAsmParser &Parser) override {
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000047 // Call the base implementation.
48 MCAsmParserExtension::Initialize(Parser);
49
Jim Grosbachd2037eb2013-02-20 22:21:35 +000050 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
51 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
52 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
Nico Rieck1558c5a2013-07-04 21:32:07 +000053 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000054 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
55 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
56 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
57 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
58 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +000059 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
Nico Riecka37acf72013-07-06 12:13:10 +000060 addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
Charles Davisc7250fa2011-05-22 21:12:15 +000061
62 // Win64 EH directives.
Jim Grosbachd2037eb2013-02-20 22:21:35 +000063 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
Charles Davisc7250fa2011-05-22 21:12:15 +000064 ".seh_proc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000065 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
Charles Davisc7250fa2011-05-22 21:12:15 +000066 ".seh_endproc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000067 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
Charles Davisc7250fa2011-05-22 21:12:15 +000068 ".seh_startchained");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000069 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
Charles Davisc7250fa2011-05-22 21:12:15 +000070 ".seh_endchained");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000071 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
Charles Davisc7250fa2011-05-22 21:12:15 +000072 ".seh_handler");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000073 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
Charles Davisc7250fa2011-05-22 21:12:15 +000074 ".seh_handlerdata");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000075 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
Charles Davisc7250fa2011-05-22 21:12:15 +000076 ".seh_pushreg");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000077 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
Charles Davisc7250fa2011-05-22 21:12:15 +000078 ".seh_setframe");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000079 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
Charles Davisc7250fa2011-05-22 21:12:15 +000080 ".seh_stackalloc");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000081 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
Charles Davisc7250fa2011-05-22 21:12:15 +000082 ".seh_savereg");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000083 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
Charles Davisc7250fa2011-05-22 21:12:15 +000084 ".seh_savexmm");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000085 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
Charles Davisc7250fa2011-05-22 21:12:15 +000086 ".seh_pushframe");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000087 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
Charles Davisc7250fa2011-05-22 21:12:15 +000088 ".seh_endprologue");
Jim Grosbachd2037eb2013-02-20 22:21:35 +000089 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +000090 }
91
92 bool ParseSectionDirectiveText(StringRef, SMLoc) {
93 return ParseSectionSwitch(".text",
94 COFF::IMAGE_SCN_CNT_CODE
95 | COFF::IMAGE_SCN_MEM_EXECUTE
96 | COFF::IMAGE_SCN_MEM_READ,
97 SectionKind::getText());
98 }
99 bool ParseSectionDirectiveData(StringRef, SMLoc) {
100 return ParseSectionSwitch(".data",
101 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
102 | COFF::IMAGE_SCN_MEM_READ
103 | COFF::IMAGE_SCN_MEM_WRITE,
104 SectionKind::getDataRel());
105 }
106 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
107 return ParseSectionSwitch(".bss",
108 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
109 | COFF::IMAGE_SCN_MEM_READ
110 | COFF::IMAGE_SCN_MEM_WRITE,
111 SectionKind::getBSS());
112 }
113
Nico Rieck1558c5a2013-07-04 21:32:07 +0000114 bool ParseDirectiveSection(StringRef, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000115 bool ParseDirectiveDef(StringRef, SMLoc);
116 bool ParseDirectiveScl(StringRef, SMLoc);
117 bool ParseDirectiveType(StringRef, SMLoc);
118 bool ParseDirectiveEndef(StringRef, SMLoc);
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000119 bool ParseDirectiveSecRel32(StringRef, SMLoc);
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000120 bool ParseDirectiveSecIdx(StringRef, SMLoc);
Rafael Espindola0766ae02014-06-06 19:26:12 +0000121 bool parseCOMDATType(COFF::COMDATType &Type);
Nico Riecka37acf72013-07-06 12:13:10 +0000122 bool ParseDirectiveLinkOnce(StringRef, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000123
Charles Davisc7250fa2011-05-22 21:12:15 +0000124 // Win64 EH directives.
125 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
126 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
127 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
128 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
129 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
130 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
Charles Davis7f6176c2011-05-24 20:06:30 +0000131 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
132 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
133 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
134 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
135 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
136 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
Charles Davisc7250fa2011-05-22 21:12:15 +0000137 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
138
139 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
Charles Davis7f6176c2011-05-24 20:06:30 +0000140 bool ParseSEHRegisterNumber(unsigned &RegNo);
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000141 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000142public:
143 COFFAsmParser() {}
144};
145
146} // end annonomous namespace.
147
Nico Rieck1558c5a2013-07-04 21:32:07 +0000148static SectionKind computeSectionKind(unsigned Flags) {
149 if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
150 return SectionKind::getText();
151 if (Flags & COFF::IMAGE_SCN_MEM_READ &&
152 (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
153 return SectionKind::getReadOnly();
154 return SectionKind::getDataRel();
155}
156
157bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) {
158 enum {
159 None = 0,
160 Alloc = 1 << 0,
161 Code = 1 << 1,
162 Load = 1 << 2,
163 InitData = 1 << 3,
164 Shared = 1 << 4,
165 NoLoad = 1 << 5,
166 NoRead = 1 << 6,
167 NoWrite = 1 << 7
168 };
169
170 bool ReadOnlyRemoved = false;
171 unsigned SecFlags = None;
172
David Majnemerbee5f752014-07-04 23:15:28 +0000173 for (char FlagChar : FlagsString) {
174 switch (FlagChar) {
Nico Rieck1558c5a2013-07-04 21:32:07 +0000175 case 'a':
176 // Ignored.
177 break;
178
179 case 'b': // bss section
180 SecFlags |= Alloc;
181 if (SecFlags & InitData)
182 return TokError("conflicting section flags 'b' and 'd'.");
183 SecFlags &= ~Load;
184 break;
185
186 case 'd': // data section
187 SecFlags |= InitData;
188 if (SecFlags & Alloc)
189 return TokError("conflicting section flags 'b' and 'd'.");
190 SecFlags &= ~NoWrite;
191 if ((SecFlags & NoLoad) == 0)
192 SecFlags |= Load;
193 break;
194
195 case 'n': // section is not loaded
196 SecFlags |= NoLoad;
197 SecFlags &= ~Load;
198 break;
199
200 case 'r': // read-only
201 ReadOnlyRemoved = false;
202 SecFlags |= NoWrite;
203 if ((SecFlags & Code) == 0)
204 SecFlags |= InitData;
205 if ((SecFlags & NoLoad) == 0)
206 SecFlags |= Load;
207 break;
208
209 case 's': // shared section
210 SecFlags |= Shared | InitData;
211 SecFlags &= ~NoWrite;
212 if ((SecFlags & NoLoad) == 0)
213 SecFlags |= Load;
214 break;
215
216 case 'w': // writable
217 SecFlags &= ~NoWrite;
218 ReadOnlyRemoved = true;
219 break;
220
221 case 'x': // executable section
222 SecFlags |= Code;
223 if ((SecFlags & NoLoad) == 0)
224 SecFlags |= Load;
225 if (!ReadOnlyRemoved)
226 SecFlags |= NoWrite;
227 break;
228
229 case 'y': // not readable
230 SecFlags |= NoRead | NoWrite;
231 break;
232
233 default:
234 return TokError("unknown flag");
235 }
236 }
237
238 *Flags = 0;
239
240 if (SecFlags == None)
241 SecFlags = InitData;
242
243 if (SecFlags & Code)
244 *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
245 if (SecFlags & InitData)
246 *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
247 if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
248 *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
249 if (SecFlags & NoLoad)
250 *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
251 if ((SecFlags & NoRead) == 0)
252 *Flags |= COFF::IMAGE_SCN_MEM_READ;
253 if ((SecFlags & NoWrite) == 0)
254 *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
255 if (SecFlags & Shared)
256 *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
257
258 return false;
259}
260
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000261/// ParseDirectiveSymbolAttribute
262/// ::= { ".weak", ... } [ identifier ( , identifier )* ]
263bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
264 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
265 .Case(".weak", MCSA_Weak)
266 .Default(MCSA_Invalid);
267 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
268 if (getLexer().isNot(AsmToken::EndOfStatement)) {
269 for (;;) {
270 StringRef Name;
271
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000272 if (getParser().parseIdentifier(Name))
Jim Grosbach38b1ed82011-07-25 17:55:35 +0000273 return TokError("expected identifier in directive");
274
275 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
276
277 getStreamer().EmitSymbolAttribute(Sym, Attr);
278
279 if (getLexer().is(AsmToken::EndOfStatement))
280 break;
281
282 if (getLexer().isNot(AsmToken::Comma))
283 return TokError("unexpected token in directive");
284 Lex();
285 }
286 }
287
288 Lex();
289 return false;
290}
291
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000292bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
293 unsigned Characteristics,
294 SectionKind Kind) {
David Majnemerc57d0382014-06-27 17:19:44 +0000295 return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
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
David Majnemerc57d0382014-06-27 17:19:44 +0000359 COFF::COMDATType Type = (COFF::COMDATType)0;
Rafael Espindola60ec3832013-11-19 19:52:52 +0000360 StringRef COMDATSymName;
361 if (getLexer().is(AsmToken::Comma)) {
David Majnemerc57d0382014-06-27 17:19:44 +0000362 Type = COFF::IMAGE_COMDAT_SELECT_ANY;;
Rafael Espindola60ec3832013-11-19 19:52:52 +0000363 Lex();
364
365 Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
366
Reid Kleckner21aedc42014-08-11 18:34:43 +0000367 if (!getLexer().is(AsmToken::Identifier))
368 return TokError("expected comdat type such as 'discard' or 'largest' "
369 "after protection bits");
370
Rafael Espindola0766ae02014-06-06 19:26:12 +0000371 if (parseCOMDATType(Type))
Rafael Espindola60ec3832013-11-19 19:52:52 +0000372 return true;
373
374 if (getLexer().isNot(AsmToken::Comma))
375 return TokError("expected comma in directive");
376 Lex();
377
378 if (getParser().parseIdentifier(COMDATSymName))
379 return TokError("expected identifier in directive");
380 }
381
Nico Rieck1558c5a2013-07-04 21:32:07 +0000382 if (getLexer().isNot(AsmToken::EndOfStatement))
383 return TokError("unexpected token in directive");
384
385 SectionKind Kind = computeSectionKind(Flags);
Saleem Abdulrasoolbdbc0082014-06-22 22:25:01 +0000386 if (Kind.isText()) {
387 const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
388 if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
389 Flags |= COFF::IMAGE_SCN_MEM_16BIT;
390 }
Rafael Espindola0766ae02014-06-06 19:26:12 +0000391 ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
Nico Rieck1558c5a2013-07-04 21:32:07 +0000392 return false;
393}
394
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000395bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
396 StringRef SymbolName;
397
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000398 if (getParser().parseIdentifier(SymbolName))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000399 return TokError("expected identifier in directive");
400
401 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
402
403 getStreamer().BeginCOFFSymbolDef(Sym);
404
405 Lex();
406 return false;
407}
408
409bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
410 int64_t SymbolStorageClass;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000411 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000412 return true;
413
414 if (getLexer().isNot(AsmToken::EndOfStatement))
415 return TokError("unexpected token in directive");
416
417 Lex();
418 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
419 return false;
420}
421
422bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
423 int64_t Type;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000424 if (getParser().parseAbsoluteExpression(Type))
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000425 return true;
426
427 if (getLexer().isNot(AsmToken::EndOfStatement))
428 return TokError("unexpected token in directive");
429
430 Lex();
431 getStreamer().EmitCOFFSymbolType(Type);
432 return false;
433}
434
435bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
436 Lex();
437 getStreamer().EndCOFFSymbolDef();
438 return false;
439}
440
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000441bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
442 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000443 if (getParser().parseIdentifier(SymbolID))
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000444 return TokError("expected identifier in directive");
Rafael Espindolad3df3d32011-12-17 01:14:52 +0000445
446 if (getLexer().isNot(AsmToken::EndOfStatement))
447 return TokError("unexpected token in directive");
448
449 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
450
451 Lex();
452 getStreamer().EmitCOFFSecRel32(Symbol);
453 return false;
454}
455
Timur Iskhodzhanovc1fb2d62013-12-20 18:15:00 +0000456bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
457 StringRef SymbolID;
458 if (getParser().parseIdentifier(SymbolID))
459 return TokError("expected identifier in directive");
460
461 if (getLexer().isNot(AsmToken::EndOfStatement))
462 return TokError("unexpected token in directive");
463
464 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
465
466 Lex();
467 getStreamer().EmitCOFFSectionIndex(Symbol);
468 return false;
469}
470
Rafael Espindola0766ae02014-06-06 19:26:12 +0000471/// ::= [ identifier ]
472bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
Rafael Espindola60ec3832013-11-19 19:52:52 +0000473 StringRef TypeId = getTok().getIdentifier();
Nico Riecka37acf72013-07-06 12:13:10 +0000474
Rafael Espindola60ec3832013-11-19 19:52:52 +0000475 Type = StringSwitch<COFF::COMDATType>(TypeId)
476 .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
477 .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
478 .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
479 .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
480 .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
481 .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
482 .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
483 .Default((COFF::COMDATType)0);
Nico Riecka37acf72013-07-06 12:13:10 +0000484
Rafael Espindola60ec3832013-11-19 19:52:52 +0000485 if (Type == 0)
486 return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
Nico Riecka37acf72013-07-06 12:13:10 +0000487
Rafael Espindola60ec3832013-11-19 19:52:52 +0000488 Lex();
Nico Riecka37acf72013-07-06 12:13:10 +0000489
Rafael Espindola60ec3832013-11-19 19:52:52 +0000490 return false;
491}
492
493/// ParseDirectiveLinkOnce
Rafael Espindola0766ae02014-06-06 19:26:12 +0000494/// ::= .linkonce [ identifier ]
Rafael Espindola60ec3832013-11-19 19:52:52 +0000495bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
496 COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
Rafael Espindola60ec3832013-11-19 19:52:52 +0000497 if (getLexer().is(AsmToken::Identifier))
Rafael Espindola0766ae02014-06-06 19:26:12 +0000498 if (parseCOMDATType(Type))
Rafael Espindola60ec3832013-11-19 19:52:52 +0000499 return true;
500
501 const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>(
502 getStreamer().getCurrentSection().first);
503
Rafael Espindola0766ae02014-06-06 19:26:12 +0000504 if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
505 return Error(Loc, "cannot make section associative with .linkonce");
Rafael Espindola60ec3832013-11-19 19:52:52 +0000506
Nico Riecka37acf72013-07-06 12:13:10 +0000507 if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
508 return Error(Loc, Twine("section '") + Current->getSectionName() +
509 "' is already linkonce");
510
Rafael Espindola0766ae02014-06-06 19:26:12 +0000511 Current->setSelection(Type);
Nico Riecka37acf72013-07-06 12:13:10 +0000512
513 if (getLexer().isNot(AsmToken::EndOfStatement))
514 return TokError("unexpected token in directive");
515
516 return false;
517}
518
Charles Davisc7250fa2011-05-22 21:12:15 +0000519bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000520 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000521 if (getParser().parseIdentifier(SymbolID))
Charles Davisc7250fa2011-05-22 21:12:15 +0000522 return true;
523
Charles Davisc7250fa2011-05-22 21:12:15 +0000524 if (getLexer().isNot(AsmToken::EndOfStatement))
525 return TokError("unexpected token in directive");
526
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000527 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
528
Charles Davisc7250fa2011-05-22 21:12:15 +0000529 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000530 getStreamer().EmitWinCFIStartProc(Symbol);
Charles Davisc7250fa2011-05-22 21:12:15 +0000531 return false;
532}
533
534bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
535 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000536 getStreamer().EmitWinCFIEndProc();
Charles Davisc7250fa2011-05-22 21:12:15 +0000537 return false;
538}
539
540bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
541 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000542 getStreamer().EmitWinCFIStartChained();
Charles Davisc7250fa2011-05-22 21:12:15 +0000543 return false;
544}
545
546bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
547 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000548 getStreamer().EmitWinCFIEndChained();
Charles Davisc7250fa2011-05-22 21:12:15 +0000549 return false;
550}
551
552bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000553 StringRef SymbolID;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000554 if (getParser().parseIdentifier(SymbolID))
Charles Davisc7250fa2011-05-22 21:12:15 +0000555 return true;
556
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000557 if (getLexer().isNot(AsmToken::Comma))
558 return TokError("you must specify one or both of @unwind or @except");
559 Lex();
Charles Davisc7250fa2011-05-22 21:12:15 +0000560 bool unwind = false, except = false;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000561 if (ParseAtUnwindOrAtExcept(unwind, except))
562 return true;
Charles Davisc7250fa2011-05-22 21:12:15 +0000563 if (getLexer().is(AsmToken::Comma)) {
564 Lex();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000565 if (ParseAtUnwindOrAtExcept(unwind, except))
Charles Davisc7250fa2011-05-22 21:12:15 +0000566 return true;
567 }
568 if (getLexer().isNot(AsmToken::EndOfStatement))
569 return TokError("unexpected token in directive");
570
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000571 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
572
Charles Davisc7250fa2011-05-22 21:12:15 +0000573 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000574 getStreamer().EmitWinEHHandler(handler, unwind, except);
Charles Davisc7250fa2011-05-22 21:12:15 +0000575 return false;
576}
577
578bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
579 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000580 getStreamer().EmitWinEHHandlerData();
Charles Davisc7250fa2011-05-22 21:12:15 +0000581 return false;
582}
583
584bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
Michael Ilseman5be22a12014-12-12 21:48:03 +0000585 unsigned Reg = 0;
Charles Davis7f6176c2011-05-24 20:06:30 +0000586 if (ParseSEHRegisterNumber(Reg))
587 return true;
588
589 if (getLexer().isNot(AsmToken::EndOfStatement))
590 return TokError("unexpected token in directive");
591
592 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000593 getStreamer().EmitWinCFIPushReg(Reg);
Charles Davis7f6176c2011-05-24 20:06:30 +0000594 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000595}
596
597bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
Michael Ilseman5be22a12014-12-12 21:48:03 +0000598 unsigned Reg = 0;
Charles Davis7f6176c2011-05-24 20:06:30 +0000599 int64_t Off;
600 if (ParseSEHRegisterNumber(Reg))
601 return true;
Charles Davis2f6ecea2011-05-25 21:43:45 +0000602 if (getLexer().isNot(AsmToken::Comma))
603 return TokError("you must specify a stack pointer offset");
604
605 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000606 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000607 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000608 return true;
609
610 if (Off & 0x0F)
611 return Error(startLoc, "offset is not a multiple of 16");
612
613 if (getLexer().isNot(AsmToken::EndOfStatement))
614 return TokError("unexpected token in directive");
615
616 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000617 getStreamer().EmitWinCFISetFrame(Reg, Off);
Charles Davis7f6176c2011-05-24 20:06:30 +0000618 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000619}
620
Charles Davisd9eafdc2011-05-23 16:43:09 +0000621bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
622 int64_t Size;
Charles Davis7f6176c2011-05-24 20:06:30 +0000623 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000624 if (getParser().parseAbsoluteExpression(Size))
Charles Davisd9eafdc2011-05-23 16:43:09 +0000625 return true;
626
Charles Davis7f6176c2011-05-24 20:06:30 +0000627 if (Size & 7)
628 return Error(startLoc, "size is not a multiple of 8");
629
Charles Davisd9eafdc2011-05-23 16:43:09 +0000630 if (getLexer().isNot(AsmToken::EndOfStatement))
631 return TokError("unexpected token in directive");
632
633 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000634 getStreamer().EmitWinCFIAllocStack(Size);
Charles Davisd9eafdc2011-05-23 16:43:09 +0000635 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000636}
637
638bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
Michael Ilseman5be22a12014-12-12 21:48:03 +0000639 unsigned Reg = 0;
Charles Davis7f6176c2011-05-24 20:06:30 +0000640 int64_t Off;
641 if (ParseSEHRegisterNumber(Reg))
642 return true;
Charles Davis828b00c2011-05-25 04:51:25 +0000643 if (getLexer().isNot(AsmToken::Comma))
Charles Davis2f6ecea2011-05-25 21:43:45 +0000644 return TokError("you must specify an offset on the stack");
Charles Davis828b00c2011-05-25 04:51:25 +0000645
646 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000647 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000648 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000649 return true;
650
651 if (Off & 7)
652 return Error(startLoc, "size is not a multiple of 8");
653
654 if (getLexer().isNot(AsmToken::EndOfStatement))
655 return TokError("unexpected token in directive");
656
657 Lex();
658 // FIXME: Err on %xmm* registers
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000659 getStreamer().EmitWinCFISaveReg(Reg, Off);
Charles Davis7f6176c2011-05-24 20:06:30 +0000660 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000661}
662
Charles Davis7f6176c2011-05-24 20:06:30 +0000663// FIXME: This method is inherently x86-specific. It should really be in the
664// x86 backend.
Charles Davisc7250fa2011-05-22 21:12:15 +0000665bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
Michael Ilseman5be22a12014-12-12 21:48:03 +0000666 unsigned Reg = 0;
Charles Davis7f6176c2011-05-24 20:06:30 +0000667 int64_t Off;
668 if (ParseSEHRegisterNumber(Reg))
669 return true;
Charles Davis828b00c2011-05-25 04:51:25 +0000670 if (getLexer().isNot(AsmToken::Comma))
Charles Davis2f6ecea2011-05-25 21:43:45 +0000671 return TokError("you must specify an offset on the stack");
Charles Davis828b00c2011-05-25 04:51:25 +0000672
673 Lex();
Charles Davis7f6176c2011-05-24 20:06:30 +0000674 SMLoc startLoc = getLexer().getLoc();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000675 if (getParser().parseAbsoluteExpression(Off))
Charles Davis7f6176c2011-05-24 20:06:30 +0000676 return true;
677
678 if (getLexer().isNot(AsmToken::EndOfStatement))
679 return TokError("unexpected token in directive");
680
681 if (Off & 0x0F)
682 return Error(startLoc, "offset is not a multiple of 16");
683
684 Lex();
685 // FIXME: Err on non-%xmm* registers
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000686 getStreamer().EmitWinCFISaveXMM(Reg, Off);
Charles Davis7f6176c2011-05-24 20:06:30 +0000687 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000688}
689
Charles Davisd9eafdc2011-05-23 16:43:09 +0000690bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
Charles Davisb0c4f392011-05-25 04:08:15 +0000691 bool Code = false;
Charles Davisd9eafdc2011-05-23 16:43:09 +0000692 StringRef CodeID;
Charles Davisb0c4f392011-05-25 04:08:15 +0000693 if (getLexer().is(AsmToken::At)) {
694 SMLoc startLoc = getLexer().getLoc();
695 Lex();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000696 if (!getParser().parseIdentifier(CodeID)) {
Charles Davisb0c4f392011-05-25 04:08:15 +0000697 if (CodeID != "code")
698 return Error(startLoc, "expected @code");
699 Code = true;
700 }
Charles Davisd9eafdc2011-05-23 16:43:09 +0000701 }
702
703 if (getLexer().isNot(AsmToken::EndOfStatement))
704 return TokError("unexpected token in directive");
705
706 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000707 getStreamer().EmitWinCFIPushFrame(Code);
Charles Davisd9eafdc2011-05-23 16:43:09 +0000708 return false;
Charles Davisc7250fa2011-05-22 21:12:15 +0000709}
710
711bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
712 Lex();
Saleem Abdulrasool7206a522014-06-29 01:52:01 +0000713 getStreamer().EmitWinCFIEndProlog();
Charles Davisc7250fa2011-05-22 21:12:15 +0000714 return false;
715}
716
717bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
718 StringRef identifier;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000719 if (getLexer().isNot(AsmToken::At))
720 return TokError("a handler attribute must begin with '@'");
Charles Davisc7250fa2011-05-22 21:12:15 +0000721 SMLoc startLoc = getLexer().getLoc();
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000722 Lex();
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000723 if (getParser().parseIdentifier(identifier))
Charles Davisc7250fa2011-05-22 21:12:15 +0000724 return Error(startLoc, "expected @unwind or @except");
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000725 if (identifier == "unwind")
Charles Davisc7250fa2011-05-22 21:12:15 +0000726 unwind = true;
Charles Davisfc1e7ce2011-05-25 01:33:42 +0000727 else if (identifier == "except")
Charles Davisc7250fa2011-05-22 21:12:15 +0000728 except = true;
729 else
730 return Error(startLoc, "expected @unwind or @except");
731 return false;
732}
733
Charles Davis7f6176c2011-05-24 20:06:30 +0000734bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
Charles Davis7f6176c2011-05-24 20:06:30 +0000735 SMLoc startLoc = getLexer().getLoc();
Charles Davis828b00c2011-05-25 04:51:25 +0000736 if (getLexer().is(AsmToken::Percent)) {
Bill Wendlingbc07a892013-06-18 07:20:20 +0000737 const MCRegisterInfo *MRI = getContext().getRegisterInfo();
Charles Davis7f6176c2011-05-24 20:06:30 +0000738 SMLoc endLoc;
739 unsigned LLVMRegNo;
740 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
Charles Davis828b00c2011-05-25 04:51:25 +0000741 return true;
Charles Davis7f6176c2011-05-24 20:06:30 +0000742
Evan Chengd60fa58b2011-07-18 20:57:22 +0000743#if 0
744 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
745 // violation so this validation code is disabled.
746
Charles Davis7f6176c2011-05-24 20:06:30 +0000747 // Check that this is a non-volatile register.
Evan Chenga83b37a2011-07-15 02:09:41 +0000748 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
Charles Davis7f6176c2011-05-24 20:06:30 +0000749 unsigned i;
750 for (i = 0; NVRegs[i] != 0; ++i)
751 if (NVRegs[i] == LLVMRegNo)
752 break;
753 if (NVRegs[i] == 0)
754 return Error(startLoc, "expected non-volatile register");
Evan Chengd60fa58b2011-07-18 20:57:22 +0000755#endif
Charles Davis7f6176c2011-05-24 20:06:30 +0000756
Bill Wendlingbc07a892013-06-18 07:20:20 +0000757 int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo);
Charles Davis7f6176c2011-05-24 20:06:30 +0000758 if (SEHRegNo < 0)
759 return Error(startLoc,"register can't be represented in SEH unwind info");
760 RegNo = SEHRegNo;
761 }
Charles Davis828b00c2011-05-25 04:51:25 +0000762 else {
763 int64_t n;
Jim Grosbachd2037eb2013-02-20 22:21:35 +0000764 if (getParser().parseAbsoluteExpression(n))
Charles Davis828b00c2011-05-25 04:51:25 +0000765 return true;
766 if (n > 15)
767 return Error(startLoc, "register number is too high");
Charles Davis7f6176c2011-05-24 20:06:30 +0000768 RegNo = n;
Charles Davis828b00c2011-05-25 04:51:25 +0000769 }
Charles Davis7f6176c2011-05-24 20:06:30 +0000770
Charles Davis7f6176c2011-05-24 20:06:30 +0000771 return false;
772}
773
Michael J. Spencerc8dbdfd2010-10-09 11:01:07 +0000774namespace llvm {
775
776MCAsmParserExtension *createCOFFAsmParser() {
777 return new COFFAsmParser;
778}
779
780}