1 //===- 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"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/MC/MCAsmInfo.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCParser/MCAsmLexer.h"
17 #include "llvm/MC/MCRegisterInfo.h"
18 #include "llvm/MC/MCSectionCOFF.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCTargetAsmParser.h"
21 #include "llvm/Support/COFF.h"
22 using namespace llvm;
23
24 namespace {
25
26 class COFFAsmParser : public MCAsmParserExtension {
27 template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
addDirectiveHandler(StringRef Directive)28 void addDirectiveHandler(StringRef Directive) {
29 MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
30 this, HandleDirective<COFFAsmParser, HandlerMethod>);
31 getParser().addDirectiveHandler(Directive, Handler);
32 }
33
34 bool ParseSectionSwitch(StringRef Section,
35 unsigned Characteristics,
36 SectionKind Kind);
37
Initialize(MCAsmParser & Parser)38 virtual void Initialize(MCAsmParser &Parser) {
39 // Call the base implementation.
40 MCAsmParserExtension::Initialize(Parser);
41
42 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
43 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
44 addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
45 addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
46 addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
47 addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
48 addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
49 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
50
51 // Win64 EH directives.
52 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
53 ".seh_proc");
54 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
55 ".seh_endproc");
56 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
57 ".seh_startchained");
58 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
59 ".seh_endchained");
60 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
61 ".seh_handler");
62 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
63 ".seh_handlerdata");
64 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushReg>(
65 ".seh_pushreg");
66 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>(
67 ".seh_setframe");
68 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
69 ".seh_stackalloc");
70 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>(
71 ".seh_savereg");
72 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>(
73 ".seh_savexmm");
74 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>(
75 ".seh_pushframe");
76 addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
77 ".seh_endprologue");
78 addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
79 }
80
ParseSectionDirectiveText(StringRef,SMLoc)81 bool ParseSectionDirectiveText(StringRef, SMLoc) {
82 return ParseSectionSwitch(".text",
83 COFF::IMAGE_SCN_CNT_CODE
84 | COFF::IMAGE_SCN_MEM_EXECUTE
85 | COFF::IMAGE_SCN_MEM_READ,
86 SectionKind::getText());
87 }
ParseSectionDirectiveData(StringRef,SMLoc)88 bool ParseSectionDirectiveData(StringRef, SMLoc) {
89 return ParseSectionSwitch(".data",
90 COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
91 | COFF::IMAGE_SCN_MEM_READ
92 | COFF::IMAGE_SCN_MEM_WRITE,
93 SectionKind::getDataRel());
94 }
ParseSectionDirectiveBSS(StringRef,SMLoc)95 bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
96 return ParseSectionSwitch(".bss",
97 COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
98 | COFF::IMAGE_SCN_MEM_READ
99 | COFF::IMAGE_SCN_MEM_WRITE,
100 SectionKind::getBSS());
101 }
102
103 bool ParseDirectiveDef(StringRef, SMLoc);
104 bool ParseDirectiveScl(StringRef, SMLoc);
105 bool ParseDirectiveType(StringRef, SMLoc);
106 bool ParseDirectiveEndef(StringRef, SMLoc);
107 bool ParseDirectiveSecRel32(StringRef, SMLoc);
108
109 // Win64 EH directives.
110 bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
111 bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
112 bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
113 bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
114 bool ParseSEHDirectiveHandler(StringRef, SMLoc);
115 bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
116 bool ParseSEHDirectivePushReg(StringRef, SMLoc);
117 bool ParseSEHDirectiveSetFrame(StringRef, SMLoc);
118 bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
119 bool ParseSEHDirectiveSaveReg(StringRef, SMLoc);
120 bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc);
121 bool ParseSEHDirectivePushFrame(StringRef, SMLoc);
122 bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
123
124 bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
125 bool ParseSEHRegisterNumber(unsigned &RegNo);
126 bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
127 public:
COFFAsmParser()128 COFFAsmParser() {}
129 };
130
131 } // end annonomous namespace.
132
133 /// ParseDirectiveSymbolAttribute
134 /// ::= { ".weak", ... } [ identifier ( , identifier )* ]
ParseDirectiveSymbolAttribute(StringRef Directive,SMLoc)135 bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
136 MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
137 .Case(".weak", MCSA_Weak)
138 .Default(MCSA_Invalid);
139 assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
140 if (getLexer().isNot(AsmToken::EndOfStatement)) {
141 for (;;) {
142 StringRef Name;
143
144 if (getParser().parseIdentifier(Name))
145 return TokError("expected identifier in directive");
146
147 MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
148
149 getStreamer().EmitSymbolAttribute(Sym, Attr);
150
151 if (getLexer().is(AsmToken::EndOfStatement))
152 break;
153
154 if (getLexer().isNot(AsmToken::Comma))
155 return TokError("unexpected token in directive");
156 Lex();
157 }
158 }
159
160 Lex();
161 return false;
162 }
163
ParseSectionSwitch(StringRef Section,unsigned Characteristics,SectionKind Kind)164 bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
165 unsigned Characteristics,
166 SectionKind Kind) {
167 if (getLexer().isNot(AsmToken::EndOfStatement))
168 return TokError("unexpected token in section switching directive");
169 Lex();
170
171 getStreamer().SwitchSection(getContext().getCOFFSection(
172 Section, Characteristics, Kind));
173
174 return false;
175 }
176
ParseDirectiveDef(StringRef,SMLoc)177 bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
178 StringRef SymbolName;
179
180 if (getParser().parseIdentifier(SymbolName))
181 return TokError("expected identifier in directive");
182
183 MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName);
184
185 getStreamer().BeginCOFFSymbolDef(Sym);
186
187 Lex();
188 return false;
189 }
190
ParseDirectiveScl(StringRef,SMLoc)191 bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
192 int64_t SymbolStorageClass;
193 if (getParser().parseAbsoluteExpression(SymbolStorageClass))
194 return true;
195
196 if (getLexer().isNot(AsmToken::EndOfStatement))
197 return TokError("unexpected token in directive");
198
199 Lex();
200 getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
201 return false;
202 }
203
ParseDirectiveType(StringRef,SMLoc)204 bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
205 int64_t Type;
206 if (getParser().parseAbsoluteExpression(Type))
207 return true;
208
209 if (getLexer().isNot(AsmToken::EndOfStatement))
210 return TokError("unexpected token in directive");
211
212 Lex();
213 getStreamer().EmitCOFFSymbolType(Type);
214 return false;
215 }
216
ParseDirectiveEndef(StringRef,SMLoc)217 bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
218 Lex();
219 getStreamer().EndCOFFSymbolDef();
220 return false;
221 }
222
ParseDirectiveSecRel32(StringRef,SMLoc)223 bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
224 StringRef SymbolID;
225 if (getParser().parseIdentifier(SymbolID))
226 return true;
227
228 if (getLexer().isNot(AsmToken::EndOfStatement))
229 return TokError("unexpected token in directive");
230
231 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
232
233 Lex();
234 getStreamer().EmitCOFFSecRel32(Symbol);
235 return false;
236 }
237
ParseSEHDirectiveStartProc(StringRef,SMLoc)238 bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) {
239 StringRef SymbolID;
240 if (getParser().parseIdentifier(SymbolID))
241 return true;
242
243 if (getLexer().isNot(AsmToken::EndOfStatement))
244 return TokError("unexpected token in directive");
245
246 MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID);
247
248 Lex();
249 getStreamer().EmitWin64EHStartProc(Symbol);
250 return false;
251 }
252
ParseSEHDirectiveEndProc(StringRef,SMLoc)253 bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) {
254 Lex();
255 getStreamer().EmitWin64EHEndProc();
256 return false;
257 }
258
ParseSEHDirectiveStartChained(StringRef,SMLoc)259 bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) {
260 Lex();
261 getStreamer().EmitWin64EHStartChained();
262 return false;
263 }
264
ParseSEHDirectiveEndChained(StringRef,SMLoc)265 bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) {
266 Lex();
267 getStreamer().EmitWin64EHEndChained();
268 return false;
269 }
270
ParseSEHDirectiveHandler(StringRef,SMLoc)271 bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) {
272 StringRef SymbolID;
273 if (getParser().parseIdentifier(SymbolID))
274 return true;
275
276 if (getLexer().isNot(AsmToken::Comma))
277 return TokError("you must specify one or both of @unwind or @except");
278 Lex();
279 bool unwind = false, except = false;
280 if (ParseAtUnwindOrAtExcept(unwind, except))
281 return true;
282 if (getLexer().is(AsmToken::Comma)) {
283 Lex();
284 if (ParseAtUnwindOrAtExcept(unwind, except))
285 return true;
286 }
287 if (getLexer().isNot(AsmToken::EndOfStatement))
288 return TokError("unexpected token in directive");
289
290 MCSymbol *handler = getContext().GetOrCreateSymbol(SymbolID);
291
292 Lex();
293 getStreamer().EmitWin64EHHandler(handler, unwind, except);
294 return false;
295 }
296
ParseSEHDirectiveHandlerData(StringRef,SMLoc)297 bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) {
298 Lex();
299 getStreamer().EmitWin64EHHandlerData();
300 return false;
301 }
302
ParseSEHDirectivePushReg(StringRef,SMLoc L)303 bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) {
304 unsigned Reg;
305 if (ParseSEHRegisterNumber(Reg))
306 return true;
307
308 if (getLexer().isNot(AsmToken::EndOfStatement))
309 return TokError("unexpected token in directive");
310
311 Lex();
312 getStreamer().EmitWin64EHPushReg(Reg);
313 return false;
314 }
315
ParseSEHDirectiveSetFrame(StringRef,SMLoc L)316 bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) {
317 unsigned Reg;
318 int64_t Off;
319 if (ParseSEHRegisterNumber(Reg))
320 return true;
321 if (getLexer().isNot(AsmToken::Comma))
322 return TokError("you must specify a stack pointer offset");
323
324 Lex();
325 SMLoc startLoc = getLexer().getLoc();
326 if (getParser().parseAbsoluteExpression(Off))
327 return true;
328
329 if (Off & 0x0F)
330 return Error(startLoc, "offset is not a multiple of 16");
331
332 if (getLexer().isNot(AsmToken::EndOfStatement))
333 return TokError("unexpected token in directive");
334
335 Lex();
336 getStreamer().EmitWin64EHSetFrame(Reg, Off);
337 return false;
338 }
339
ParseSEHDirectiveAllocStack(StringRef,SMLoc)340 bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) {
341 int64_t Size;
342 SMLoc startLoc = getLexer().getLoc();
343 if (getParser().parseAbsoluteExpression(Size))
344 return true;
345
346 if (Size & 7)
347 return Error(startLoc, "size is not a multiple of 8");
348
349 if (getLexer().isNot(AsmToken::EndOfStatement))
350 return TokError("unexpected token in directive");
351
352 Lex();
353 getStreamer().EmitWin64EHAllocStack(Size);
354 return false;
355 }
356
ParseSEHDirectiveSaveReg(StringRef,SMLoc L)357 bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) {
358 unsigned Reg;
359 int64_t Off;
360 if (ParseSEHRegisterNumber(Reg))
361 return true;
362 if (getLexer().isNot(AsmToken::Comma))
363 return TokError("you must specify an offset on the stack");
364
365 Lex();
366 SMLoc startLoc = getLexer().getLoc();
367 if (getParser().parseAbsoluteExpression(Off))
368 return true;
369
370 if (Off & 7)
371 return Error(startLoc, "size is not a multiple of 8");
372
373 if (getLexer().isNot(AsmToken::EndOfStatement))
374 return TokError("unexpected token in directive");
375
376 Lex();
377 // FIXME: Err on %xmm* registers
378 getStreamer().EmitWin64EHSaveReg(Reg, Off);
379 return false;
380 }
381
382 // FIXME: This method is inherently x86-specific. It should really be in the
383 // x86 backend.
ParseSEHDirectiveSaveXMM(StringRef,SMLoc L)384 bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) {
385 unsigned Reg;
386 int64_t Off;
387 if (ParseSEHRegisterNumber(Reg))
388 return true;
389 if (getLexer().isNot(AsmToken::Comma))
390 return TokError("you must specify an offset on the stack");
391
392 Lex();
393 SMLoc startLoc = getLexer().getLoc();
394 if (getParser().parseAbsoluteExpression(Off))
395 return true;
396
397 if (getLexer().isNot(AsmToken::EndOfStatement))
398 return TokError("unexpected token in directive");
399
400 if (Off & 0x0F)
401 return Error(startLoc, "offset is not a multiple of 16");
402
403 Lex();
404 // FIXME: Err on non-%xmm* registers
405 getStreamer().EmitWin64EHSaveXMM(Reg, Off);
406 return false;
407 }
408
ParseSEHDirectivePushFrame(StringRef,SMLoc)409 bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) {
410 bool Code = false;
411 StringRef CodeID;
412 if (getLexer().is(AsmToken::At)) {
413 SMLoc startLoc = getLexer().getLoc();
414 Lex();
415 if (!getParser().parseIdentifier(CodeID)) {
416 if (CodeID != "code")
417 return Error(startLoc, "expected @code");
418 Code = true;
419 }
420 }
421
422 if (getLexer().isNot(AsmToken::EndOfStatement))
423 return TokError("unexpected token in directive");
424
425 Lex();
426 getStreamer().EmitWin64EHPushFrame(Code);
427 return false;
428 }
429
ParseSEHDirectiveEndProlog(StringRef,SMLoc)430 bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) {
431 Lex();
432 getStreamer().EmitWin64EHEndProlog();
433 return false;
434 }
435
ParseAtUnwindOrAtExcept(bool & unwind,bool & except)436 bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
437 StringRef identifier;
438 if (getLexer().isNot(AsmToken::At))
439 return TokError("a handler attribute must begin with '@'");
440 SMLoc startLoc = getLexer().getLoc();
441 Lex();
442 if (getParser().parseIdentifier(identifier))
443 return Error(startLoc, "expected @unwind or @except");
444 if (identifier == "unwind")
445 unwind = true;
446 else if (identifier == "except")
447 except = true;
448 else
449 return Error(startLoc, "expected @unwind or @except");
450 return false;
451 }
452
ParseSEHRegisterNumber(unsigned & RegNo)453 bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) {
454 SMLoc startLoc = getLexer().getLoc();
455 if (getLexer().is(AsmToken::Percent)) {
456 const MCRegisterInfo &MRI = getContext().getRegisterInfo();
457 SMLoc endLoc;
458 unsigned LLVMRegNo;
459 if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc))
460 return true;
461
462 #if 0
463 // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering
464 // violation so this validation code is disabled.
465
466 // Check that this is a non-volatile register.
467 const unsigned *NVRegs = TAI.getCalleeSavedRegs();
468 unsigned i;
469 for (i = 0; NVRegs[i] != 0; ++i)
470 if (NVRegs[i] == LLVMRegNo)
471 break;
472 if (NVRegs[i] == 0)
473 return Error(startLoc, "expected non-volatile register");
474 #endif
475
476 int SEHRegNo = MRI.getSEHRegNum(LLVMRegNo);
477 if (SEHRegNo < 0)
478 return Error(startLoc,"register can't be represented in SEH unwind info");
479 RegNo = SEHRegNo;
480 }
481 else {
482 int64_t n;
483 if (getParser().parseAbsoluteExpression(n))
484 return true;
485 if (n > 15)
486 return Error(startLoc, "register number is too high");
487 RegNo = n;
488 }
489
490 return false;
491 }
492
493 namespace llvm {
494
createCOFFAsmParser()495 MCAsmParserExtension *createCOFFAsmParser() {
496 return new COFFAsmParser;
497 }
498
499 }
500