1218885Sdim//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
2218885Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6218885Sdim//
7218885Sdim//===----------------------------------------------------------------------===//
8218885Sdim
9321369Sdim#include "llvm/ADT/StringRef.h"
10226633Sdim#include "llvm/ADT/StringSwitch.h"
11321369Sdim#include "llvm/ADT/Triple.h"
12218885Sdim#include "llvm/ADT/Twine.h"
13321369Sdim#include "llvm/BinaryFormat/COFF.h"
14218885Sdim#include "llvm/MC/MCContext.h"
15321369Sdim#include "llvm/MC/MCDirectives.h"
16276479Sdim#include "llvm/MC/MCObjectFileInfo.h"
17218885Sdim#include "llvm/MC/MCParser/MCAsmLexer.h"
18321369Sdim#include "llvm/MC/MCParser/MCAsmParserExtension.h"
19309124Sdim#include "llvm/MC/MCParser/MCTargetAsmParser.h"
20226633Sdim#include "llvm/MC/MCRegisterInfo.h"
21218885Sdim#include "llvm/MC/MCSectionCOFF.h"
22218885Sdim#include "llvm/MC/MCStreamer.h"
23321369Sdim#include "llvm/MC/SectionKind.h"
24321369Sdim#include "llvm/Support/SMLoc.h"
25321369Sdim#include <cassert>
26321369Sdim#include <cstdint>
27321369Sdim#include <limits>
28321369Sdim#include <utility>
29321369Sdim
30218885Sdimusing namespace llvm;
31218885Sdim
32218885Sdimnamespace {
33218885Sdim
34218885Sdimclass COFFAsmParser : public MCAsmParserExtension {
35249423Sdim  template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
36249423Sdim  void addDirectiveHandler(StringRef Directive) {
37249423Sdim    MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
38249423Sdim        this, HandleDirective<COFFAsmParser, HandlerMethod>);
39249423Sdim    getParser().addDirectiveHandler(Directive, Handler);
40218885Sdim  }
41218885Sdim
42218885Sdim  bool ParseSectionSwitch(StringRef Section,
43218885Sdim                          unsigned Characteristics,
44218885Sdim                          SectionKind Kind);
45218885Sdim
46261991Sdim  bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
47261991Sdim                          SectionKind Kind, StringRef COMDATSymName,
48276479Sdim                          COFF::COMDATType Type);
49261991Sdim
50261991Sdim  bool ParseSectionName(StringRef &SectionName);
51314564Sdim  bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
52314564Sdim                         unsigned *Flags);
53261991Sdim
54276479Sdim  void Initialize(MCAsmParser &Parser) override {
55218885Sdim    // Call the base implementation.
56218885Sdim    MCAsmParserExtension::Initialize(Parser);
57218885Sdim
58249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
59249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
60249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
61261991Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
62249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
63249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
64249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
65249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
66249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
67341825Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
68341825Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
69276479Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
70261991Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
71341825Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
72360784Sdim    addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
73223017Sdim
74223017Sdim    // Win64 EH directives.
75249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
76223017Sdim                                                                   ".seh_proc");
77249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
78223017Sdim                                                                ".seh_endproc");
79249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
80223017Sdim                                                           ".seh_startchained");
81249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
82223017Sdim                                                             ".seh_endchained");
83249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
84223017Sdim                                                                ".seh_handler");
85249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
86223017Sdim                                                            ".seh_handlerdata");
87249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
88223017Sdim                                                             ".seh_stackalloc");
89249423Sdim    addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
90223017Sdim                                                            ".seh_endprologue");
91218885Sdim  }
92218885Sdim
93218885Sdim  bool ParseSectionDirectiveText(StringRef, SMLoc) {
94218885Sdim    return ParseSectionSwitch(".text",
95218885Sdim                              COFF::IMAGE_SCN_CNT_CODE
96218885Sdim                            | COFF::IMAGE_SCN_MEM_EXECUTE
97218885Sdim                            | COFF::IMAGE_SCN_MEM_READ,
98218885Sdim                              SectionKind::getText());
99218885Sdim  }
100321369Sdim
101218885Sdim  bool ParseSectionDirectiveData(StringRef, SMLoc) {
102296417Sdim    return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
103296417Sdim                                           COFF::IMAGE_SCN_MEM_READ |
104296417Sdim                                           COFF::IMAGE_SCN_MEM_WRITE,
105296417Sdim                              SectionKind::getData());
106218885Sdim  }
107321369Sdim
108218885Sdim  bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
109218885Sdim    return ParseSectionSwitch(".bss",
110218885Sdim                              COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
111218885Sdim                            | COFF::IMAGE_SCN_MEM_READ
112218885Sdim                            | COFF::IMAGE_SCN_MEM_WRITE,
113218885Sdim                              SectionKind::getBSS());
114218885Sdim  }
115218885Sdim
116261991Sdim  bool ParseDirectiveSection(StringRef, SMLoc);
117218885Sdim  bool ParseDirectiveDef(StringRef, SMLoc);
118218885Sdim  bool ParseDirectiveScl(StringRef, SMLoc);
119218885Sdim  bool ParseDirectiveType(StringRef, SMLoc);
120218885Sdim  bool ParseDirectiveEndef(StringRef, SMLoc);
121234353Sdim  bool ParseDirectiveSecRel32(StringRef, SMLoc);
122276479Sdim  bool ParseDirectiveSecIdx(StringRef, SMLoc);
123288943Sdim  bool ParseDirectiveSafeSEH(StringRef, SMLoc);
124341825Sdim  bool ParseDirectiveSymIdx(StringRef, SMLoc);
125276479Sdim  bool parseCOMDATType(COFF::COMDATType &Type);
126261991Sdim  bool ParseDirectiveLinkOnce(StringRef, SMLoc);
127341825Sdim  bool ParseDirectiveRVA(StringRef, SMLoc);
128218885Sdim
129223017Sdim  // Win64 EH directives.
130223017Sdim  bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
131223017Sdim  bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
132223017Sdim  bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
133223017Sdim  bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
134223017Sdim  bool ParseSEHDirectiveHandler(StringRef, SMLoc);
135223017Sdim  bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
136223017Sdim  bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
137223017Sdim  bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
138223017Sdim
139223017Sdim  bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
140223017Sdim  bool ParseSEHRegisterNumber(unsigned &RegNo);
141226633Sdim  bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
142321369Sdim
143218885Sdimpublic:
144321369Sdim  COFFAsmParser() = default;
145218885Sdim};
146218885Sdim
147360784Sdim} // end anonymous namespace.
148218885Sdim
149261991Sdimstatic SectionKind computeSectionKind(unsigned Flags) {
150261991Sdim  if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
151261991Sdim    return SectionKind::getText();
152261991Sdim  if (Flags & COFF::IMAGE_SCN_MEM_READ &&
153261991Sdim      (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
154261991Sdim    return SectionKind::getReadOnly();
155296417Sdim  return SectionKind::getData();
156261991Sdim}
157261991Sdim
158314564Sdimbool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
159314564Sdim                                      StringRef FlagsString, unsigned *Flags) {
160261991Sdim  enum {
161314564Sdim    None        = 0,
162314564Sdim    Alloc       = 1 << 0,
163314564Sdim    Code        = 1 << 1,
164314564Sdim    Load        = 1 << 2,
165314564Sdim    InitData    = 1 << 3,
166314564Sdim    Shared      = 1 << 4,
167314564Sdim    NoLoad      = 1 << 5,
168314564Sdim    NoRead      = 1 << 6,
169314564Sdim    NoWrite     = 1 << 7,
170314564Sdim    Discardable = 1 << 8,
171261991Sdim  };
172261991Sdim
173261991Sdim  bool ReadOnlyRemoved = false;
174261991Sdim  unsigned SecFlags = None;
175261991Sdim
176276479Sdim  for (char FlagChar : FlagsString) {
177276479Sdim    switch (FlagChar) {
178261991Sdim    case 'a':
179261991Sdim      // Ignored.
180261991Sdim      break;
181261991Sdim
182261991Sdim    case 'b': // bss section
183261991Sdim      SecFlags |= Alloc;
184261991Sdim      if (SecFlags & InitData)
185261991Sdim        return TokError("conflicting section flags 'b' and 'd'.");
186261991Sdim      SecFlags &= ~Load;
187261991Sdim      break;
188261991Sdim
189261991Sdim    case 'd': // data section
190261991Sdim      SecFlags |= InitData;
191261991Sdim      if (SecFlags & Alloc)
192261991Sdim        return TokError("conflicting section flags 'b' and 'd'.");
193261991Sdim      SecFlags &= ~NoWrite;
194261991Sdim      if ((SecFlags & NoLoad) == 0)
195261991Sdim        SecFlags |= Load;
196261991Sdim      break;
197261991Sdim
198261991Sdim    case 'n': // section is not loaded
199261991Sdim      SecFlags |= NoLoad;
200261991Sdim      SecFlags &= ~Load;
201261991Sdim      break;
202261991Sdim
203314564Sdim    case 'D': // discardable
204314564Sdim      SecFlags |= Discardable;
205314564Sdim      break;
206314564Sdim
207261991Sdim    case 'r': // read-only
208261991Sdim      ReadOnlyRemoved = false;
209261991Sdim      SecFlags |= NoWrite;
210261991Sdim      if ((SecFlags & Code) == 0)
211261991Sdim        SecFlags |= InitData;
212261991Sdim      if ((SecFlags & NoLoad) == 0)
213261991Sdim        SecFlags |= Load;
214261991Sdim      break;
215261991Sdim
216261991Sdim    case 's': // shared section
217261991Sdim      SecFlags |= Shared | InitData;
218261991Sdim      SecFlags &= ~NoWrite;
219261991Sdim      if ((SecFlags & NoLoad) == 0)
220261991Sdim        SecFlags |= Load;
221261991Sdim      break;
222261991Sdim
223261991Sdim    case 'w': // writable
224261991Sdim      SecFlags &= ~NoWrite;
225261991Sdim      ReadOnlyRemoved = true;
226261991Sdim      break;
227261991Sdim
228261991Sdim    case 'x': // executable section
229261991Sdim      SecFlags |= Code;
230261991Sdim      if ((SecFlags & NoLoad) == 0)
231261991Sdim        SecFlags |= Load;
232261991Sdim      if (!ReadOnlyRemoved)
233261991Sdim        SecFlags |= NoWrite;
234261991Sdim      break;
235261991Sdim
236261991Sdim    case 'y': // not readable
237261991Sdim      SecFlags |= NoRead | NoWrite;
238261991Sdim      break;
239261991Sdim
240261991Sdim    default:
241261991Sdim      return TokError("unknown flag");
242261991Sdim    }
243261991Sdim  }
244261991Sdim
245261991Sdim  *Flags = 0;
246261991Sdim
247261991Sdim  if (SecFlags == None)
248261991Sdim    SecFlags = InitData;
249261991Sdim
250261991Sdim  if (SecFlags & Code)
251261991Sdim    *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
252261991Sdim  if (SecFlags & InitData)
253261991Sdim    *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
254261991Sdim  if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
255261991Sdim    *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
256261991Sdim  if (SecFlags & NoLoad)
257261991Sdim    *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
258314564Sdim  if ((SecFlags & Discardable) ||
259314564Sdim      MCSectionCOFF::isImplicitlyDiscardable(SectionName))
260314564Sdim    *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
261261991Sdim  if ((SecFlags & NoRead) == 0)
262261991Sdim    *Flags |= COFF::IMAGE_SCN_MEM_READ;
263261991Sdim  if ((SecFlags & NoWrite) == 0)
264261991Sdim    *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
265261991Sdim  if (SecFlags & Shared)
266261991Sdim    *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
267261991Sdim
268261991Sdim  return false;
269261991Sdim}
270261991Sdim
271226633Sdim/// ParseDirectiveSymbolAttribute
272226633Sdim///  ::= { ".weak", ... } [ identifier ( , identifier )* ]
273226633Sdimbool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
274226633Sdim  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
275226633Sdim    .Case(".weak", MCSA_Weak)
276226633Sdim    .Default(MCSA_Invalid);
277226633Sdim  assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
278226633Sdim  if (getLexer().isNot(AsmToken::EndOfStatement)) {
279321369Sdim    while (true) {
280226633Sdim      StringRef Name;
281226633Sdim
282249423Sdim      if (getParser().parseIdentifier(Name))
283226633Sdim        return TokError("expected identifier in directive");
284226633Sdim
285288943Sdim      MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
286226633Sdim
287226633Sdim      getStreamer().EmitSymbolAttribute(Sym, Attr);
288226633Sdim
289226633Sdim      if (getLexer().is(AsmToken::EndOfStatement))
290226633Sdim        break;
291226633Sdim
292226633Sdim      if (getLexer().isNot(AsmToken::Comma))
293226633Sdim        return TokError("unexpected token in directive");
294226633Sdim      Lex();
295226633Sdim    }
296226633Sdim  }
297226633Sdim
298226633Sdim  Lex();
299226633Sdim  return false;
300226633Sdim}
301226633Sdim
302218885Sdimbool COFFAsmParser::ParseSectionSwitch(StringRef Section,
303218885Sdim                                       unsigned Characteristics,
304218885Sdim                                       SectionKind Kind) {
305276479Sdim  return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
306261991Sdim}
307261991Sdim
308261991Sdimbool COFFAsmParser::ParseSectionSwitch(StringRef Section,
309261991Sdim                                       unsigned Characteristics,
310261991Sdim                                       SectionKind Kind,
311261991Sdim                                       StringRef COMDATSymName,
312276479Sdim                                       COFF::COMDATType Type) {
313218885Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
314218885Sdim    return TokError("unexpected token in section switching directive");
315218885Sdim  Lex();
316218885Sdim
317218885Sdim  getStreamer().SwitchSection(getContext().getCOFFSection(
318276479Sdim      Section, Characteristics, Kind, COMDATSymName, Type));
319218885Sdim
320218885Sdim  return false;
321218885Sdim}
322218885Sdim
323261991Sdimbool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
324261991Sdim  if (!getLexer().is(AsmToken::Identifier))
325261991Sdim    return true;
326261991Sdim
327261991Sdim  SectionName = getTok().getIdentifier();
328261991Sdim  Lex();
329261991Sdim  return false;
330261991Sdim}
331261991Sdim
332261991Sdim// .section name [, "flags"] [, identifier [ identifier ], identifier]
333261991Sdim//
334261991Sdim// Supported flags:
335261991Sdim//   a: Ignored.
336261991Sdim//   b: BSS section (uninitialized data)
337261991Sdim//   d: data section (initialized data)
338314564Sdim//   n: "noload" section (removed by linker)
339314564Sdim//   D: Discardable section
340261991Sdim//   r: Readable section
341261991Sdim//   s: Shared section
342261991Sdim//   w: Writable section
343261991Sdim//   x: Executable section
344261991Sdim//   y: Not-readable section (clears 'r')
345261991Sdim//
346261991Sdim// Subsections are not supported.
347261991Sdimbool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
348261991Sdim  StringRef SectionName;
349261991Sdim
350261991Sdim  if (ParseSectionName(SectionName))
351261991Sdim    return TokError("expected identifier in directive");
352261991Sdim
353261991Sdim  unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
354261991Sdim                   COFF::IMAGE_SCN_MEM_READ |
355261991Sdim                   COFF::IMAGE_SCN_MEM_WRITE;
356261991Sdim
357261991Sdim  if (getLexer().is(AsmToken::Comma)) {
358261991Sdim    Lex();
359261991Sdim
360261991Sdim    if (getLexer().isNot(AsmToken::String))
361261991Sdim      return TokError("expected string in directive");
362261991Sdim
363261991Sdim    StringRef FlagsStr = getTok().getStringContents();
364261991Sdim    Lex();
365261991Sdim
366314564Sdim    if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
367261991Sdim      return true;
368261991Sdim  }
369261991Sdim
370276479Sdim  COFF::COMDATType Type = (COFF::COMDATType)0;
371261991Sdim  StringRef COMDATSymName;
372261991Sdim  if (getLexer().is(AsmToken::Comma)) {
373288943Sdim    Type = COFF::IMAGE_COMDAT_SELECT_ANY;
374261991Sdim    Lex();
375261991Sdim
376261991Sdim    Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
377261991Sdim
378280031Sdim    if (!getLexer().is(AsmToken::Identifier))
379280031Sdim      return TokError("expected comdat type such as 'discard' or 'largest' "
380280031Sdim                      "after protection bits");
381280031Sdim
382276479Sdim    if (parseCOMDATType(Type))
383261991Sdim      return true;
384261991Sdim
385261991Sdim    if (getLexer().isNot(AsmToken::Comma))
386261991Sdim      return TokError("expected comma in directive");
387261991Sdim    Lex();
388261991Sdim
389261991Sdim    if (getParser().parseIdentifier(COMDATSymName))
390261991Sdim      return TokError("expected identifier in directive");
391261991Sdim  }
392261991Sdim
393261991Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
394261991Sdim    return TokError("unexpected token in directive");
395261991Sdim
396261991Sdim  SectionKind Kind = computeSectionKind(Flags);
397276479Sdim  if (Kind.isText()) {
398276479Sdim    const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
399276479Sdim    if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
400276479Sdim      Flags |= COFF::IMAGE_SCN_MEM_16BIT;
401276479Sdim  }
402276479Sdim  ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
403261991Sdim  return false;
404261991Sdim}
405261991Sdim
406218885Sdimbool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
407218885Sdim  StringRef SymbolName;
408218885Sdim
409249423Sdim  if (getParser().parseIdentifier(SymbolName))
410218885Sdim    return TokError("expected identifier in directive");
411218885Sdim
412288943Sdim  MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
413218885Sdim
414218885Sdim  getStreamer().BeginCOFFSymbolDef(Sym);
415218885Sdim
416218885Sdim  Lex();
417218885Sdim  return false;
418218885Sdim}
419218885Sdim
420218885Sdimbool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
421218885Sdim  int64_t SymbolStorageClass;
422249423Sdim  if (getParser().parseAbsoluteExpression(SymbolStorageClass))
423218885Sdim    return true;
424218885Sdim
425218885Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
426218885Sdim    return TokError("unexpected token in directive");
427218885Sdim
428218885Sdim  Lex();
429218885Sdim  getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
430218885Sdim  return false;
431218885Sdim}
432218885Sdim
433218885Sdimbool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
434218885Sdim  int64_t Type;
435249423Sdim  if (getParser().parseAbsoluteExpression(Type))
436218885Sdim    return true;
437218885Sdim
438218885Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
439218885Sdim    return TokError("unexpected token in directive");
440218885Sdim
441218885Sdim  Lex();
442218885Sdim  getStreamer().EmitCOFFSymbolType(Type);
443218885Sdim  return false;
444218885Sdim}
445218885Sdim
446218885Sdimbool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
447218885Sdim  Lex();
448218885Sdim  getStreamer().EndCOFFSymbolDef();
449218885Sdim  return false;
450218885Sdim}
451218885Sdim
452234353Sdimbool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
453234353Sdim  StringRef SymbolID;
454249423Sdim  if (getParser().parseIdentifier(SymbolID))
455276479Sdim    return TokError("expected identifier in directive");
456234353Sdim
457314564Sdim  int64_t Offset = 0;
458314564Sdim  SMLoc OffsetLoc;
459314564Sdim  if (getLexer().is(AsmToken::Plus)) {
460314564Sdim    OffsetLoc = getLexer().getLoc();
461314564Sdim    if (getParser().parseAbsoluteExpression(Offset))
462314564Sdim      return true;
463314564Sdim  }
464314564Sdim
465234353Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
466234353Sdim    return TokError("unexpected token in directive");
467234353Sdim
468321369Sdim  if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
469321369Sdim    return Error(
470321369Sdim        OffsetLoc,
471321369Sdim        "invalid '.secrel32' directive offset, can't be less "
472321369Sdim        "than zero or greater than std::numeric_limits<uint32_t>::max()");
473314564Sdim
474288943Sdim  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
475234353Sdim
476234353Sdim  Lex();
477314564Sdim  getStreamer().EmitCOFFSecRel32(Symbol, Offset);
478234353Sdim  return false;
479234353Sdim}
480234353Sdim
481341825Sdimbool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
482341825Sdim  auto parseOp = [&]() -> bool {
483341825Sdim    StringRef SymbolID;
484341825Sdim    if (getParser().parseIdentifier(SymbolID))
485341825Sdim      return TokError("expected identifier in directive");
486341825Sdim
487341825Sdim    int64_t Offset = 0;
488341825Sdim    SMLoc OffsetLoc;
489341825Sdim    if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
490341825Sdim      OffsetLoc = getLexer().getLoc();
491341825Sdim      if (getParser().parseAbsoluteExpression(Offset))
492341825Sdim        return true;
493341825Sdim    }
494341825Sdim
495341825Sdim    if (Offset < std::numeric_limits<int32_t>::min() ||
496341825Sdim        Offset > std::numeric_limits<int32_t>::max())
497341825Sdim      return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
498341825Sdim                              "than -2147483648 or greater than "
499341825Sdim                              "2147483647");
500341825Sdim
501341825Sdim    MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
502341825Sdim
503341825Sdim    getStreamer().EmitCOFFImgRel32(Symbol, Offset);
504341825Sdim    return false;
505341825Sdim  };
506341825Sdim
507341825Sdim  if (getParser().parseMany(parseOp))
508341825Sdim    return addErrorSuffix(" in directive");
509341825Sdim  return false;
510341825Sdim}
511341825Sdim
512288943Sdimbool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
513288943Sdim  StringRef SymbolID;
514288943Sdim  if (getParser().parseIdentifier(SymbolID))
515288943Sdim    return TokError("expected identifier in directive");
516288943Sdim
517288943Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
518288943Sdim    return TokError("unexpected token in directive");
519288943Sdim
520288943Sdim  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
521288943Sdim
522288943Sdim  Lex();
523288943Sdim  getStreamer().EmitCOFFSafeSEH(Symbol);
524288943Sdim  return false;
525288943Sdim}
526288943Sdim
527276479Sdimbool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
528276479Sdim  StringRef SymbolID;
529276479Sdim  if (getParser().parseIdentifier(SymbolID))
530276479Sdim    return TokError("expected identifier in directive");
531276479Sdim
532276479Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
533276479Sdim    return TokError("unexpected token in directive");
534276479Sdim
535288943Sdim  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
536276479Sdim
537276479Sdim  Lex();
538276479Sdim  getStreamer().EmitCOFFSectionIndex(Symbol);
539276479Sdim  return false;
540276479Sdim}
541276479Sdim
542341825Sdimbool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
543341825Sdim  StringRef SymbolID;
544341825Sdim  if (getParser().parseIdentifier(SymbolID))
545341825Sdim    return TokError("expected identifier in directive");
546341825Sdim
547341825Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
548341825Sdim    return TokError("unexpected token in directive");
549341825Sdim
550341825Sdim  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
551341825Sdim
552341825Sdim  Lex();
553341825Sdim  getStreamer().EmitCOFFSymbolIndex(Symbol);
554341825Sdim  return false;
555341825Sdim}
556341825Sdim
557276479Sdim/// ::= [ identifier ]
558276479Sdimbool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
559261991Sdim  StringRef TypeId = getTok().getIdentifier();
560261991Sdim
561261991Sdim  Type = StringSwitch<COFF::COMDATType>(TypeId)
562261991Sdim    .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
563261991Sdim    .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
564261991Sdim    .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
565261991Sdim    .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
566261991Sdim    .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
567261991Sdim    .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
568261991Sdim    .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
569261991Sdim    .Default((COFF::COMDATType)0);
570261991Sdim
571261991Sdim  if (Type == 0)
572261991Sdim    return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
573261991Sdim
574261991Sdim  Lex();
575261991Sdim
576261991Sdim  return false;
577261991Sdim}
578261991Sdim
579261991Sdim/// ParseDirectiveLinkOnce
580276479Sdim///  ::= .linkonce [ identifier ]
581261991Sdimbool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
582261991Sdim  COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
583261991Sdim  if (getLexer().is(AsmToken::Identifier))
584276479Sdim    if (parseCOMDATType(Type))
585261991Sdim      return true;
586261991Sdim
587314564Sdim  const MCSectionCOFF *Current =
588314564Sdim      static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
589261991Sdim
590276479Sdim  if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
591276479Sdim    return Error(Loc, "cannot make section associative with .linkonce");
592261991Sdim
593261991Sdim  if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
594261991Sdim    return Error(Loc, Twine("section '") + Current->getSectionName() +
595261991Sdim                                                       "' is already linkonce");
596261991Sdim
597276479Sdim  Current->setSelection(Type);
598261991Sdim
599261991Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
600261991Sdim    return TokError("unexpected token in directive");
601261991Sdim
602261991Sdim  return false;
603261991Sdim}
604261991Sdim
605327952Sdimbool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
606223017Sdim  StringRef SymbolID;
607249423Sdim  if (getParser().parseIdentifier(SymbolID))
608223017Sdim    return true;
609223017Sdim
610223017Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
611223017Sdim    return TokError("unexpected token in directive");
612223017Sdim
613288943Sdim  MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
614223017Sdim
615223017Sdim  Lex();
616327952Sdim  getStreamer().EmitWinCFIStartProc(Symbol, Loc);
617223017Sdim  return false;
618223017Sdim}
619223017Sdim
620327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
621223017Sdim  Lex();
622327952Sdim  getStreamer().EmitWinCFIEndProc(Loc);
623223017Sdim  return false;
624223017Sdim}
625223017Sdim
626327952Sdimbool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
627223017Sdim  Lex();
628327952Sdim  getStreamer().EmitWinCFIStartChained(Loc);
629223017Sdim  return false;
630223017Sdim}
631223017Sdim
632327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
633223017Sdim  Lex();
634327952Sdim  getStreamer().EmitWinCFIEndChained(Loc);
635223017Sdim  return false;
636223017Sdim}
637223017Sdim
638327952Sdimbool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
639223017Sdim  StringRef SymbolID;
640249423Sdim  if (getParser().parseIdentifier(SymbolID))
641223017Sdim    return true;
642223017Sdim
643223017Sdim  if (getLexer().isNot(AsmToken::Comma))
644223017Sdim    return TokError("you must specify one or both of @unwind or @except");
645223017Sdim  Lex();
646223017Sdim  bool unwind = false, except = false;
647223017Sdim  if (ParseAtUnwindOrAtExcept(unwind, except))
648223017Sdim    return true;
649223017Sdim  if (getLexer().is(AsmToken::Comma)) {
650223017Sdim    Lex();
651223017Sdim    if (ParseAtUnwindOrAtExcept(unwind, except))
652223017Sdim      return true;
653223017Sdim  }
654223017Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
655223017Sdim    return TokError("unexpected token in directive");
656223017Sdim
657288943Sdim  MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
658223017Sdim
659223017Sdim  Lex();
660327952Sdim  getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
661223017Sdim  return false;
662223017Sdim}
663223017Sdim
664327952Sdimbool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
665223017Sdim  Lex();
666276479Sdim  getStreamer().EmitWinEHHandlerData();
667223017Sdim  return false;
668223017Sdim}
669223017Sdim
670327952Sdimbool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
671223017Sdim  int64_t Size;
672249423Sdim  if (getParser().parseAbsoluteExpression(Size))
673223017Sdim    return true;
674223017Sdim
675223017Sdim  if (getLexer().isNot(AsmToken::EndOfStatement))
676223017Sdim    return TokError("unexpected token in directive");
677223017Sdim
678223017Sdim  Lex();
679327952Sdim  getStreamer().EmitWinCFIAllocStack(Size, Loc);
680223017Sdim  return false;
681223017Sdim}
682223017Sdim
683327952Sdimbool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
684223017Sdim  Lex();
685327952Sdim  getStreamer().EmitWinCFIEndProlog(Loc);
686223017Sdim  return false;
687223017Sdim}
688223017Sdim
689223017Sdimbool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
690223017Sdim  StringRef identifier;
691223017Sdim  if (getLexer().isNot(AsmToken::At))
692223017Sdim    return TokError("a handler attribute must begin with '@'");
693223017Sdim  SMLoc startLoc = getLexer().getLoc();
694223017Sdim  Lex();
695249423Sdim  if (getParser().parseIdentifier(identifier))
696223017Sdim    return Error(startLoc, "expected @unwind or @except");
697223017Sdim  if (identifier == "unwind")
698223017Sdim    unwind = true;
699223017Sdim  else if (identifier == "except")
700223017Sdim    except = true;
701223017Sdim  else
702223017Sdim    return Error(startLoc, "expected @unwind or @except");
703223017Sdim  return false;
704223017Sdim}
705223017Sdim
706218885Sdimnamespace llvm {
707218885Sdim
708218885SdimMCAsmParserExtension *createCOFFAsmParser() {
709218885Sdim  return new COFFAsmParser;
710218885Sdim}
711218885Sdim
712321369Sdim} // end namespace llvm
713