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