1//===- ELFAsmParser.cpp - ELF 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/MCSectionELF.h"
18#include "llvm/MC/MCStreamer.h"
19#include "llvm/Support/ELF.h"
20using namespace llvm;
21
22namespace {
23
24class ELFAsmParser : public MCAsmParserExtension {
25  template<bool (ELFAsmParser::*Handler)(StringRef, SMLoc)>
26  void AddDirectiveHandler(StringRef Directive) {
27    getParser().AddDirectiveHandler(this, Directive,
28                                    HandleDirective<ELFAsmParser, Handler>);
29  }
30
31  bool ParseSectionSwitch(StringRef Section, unsigned Type,
32                          unsigned Flags, SectionKind Kind);
33  bool SeenIdent;
34
35public:
36  ELFAsmParser() : SeenIdent(false) {
37    BracketExpressionsSupported = true;
38  }
39
40  virtual void Initialize(MCAsmParser &Parser) {
41    // Call the base implementation.
42    this->MCAsmParserExtension::Initialize(Parser);
43
44    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data");
45    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text");
46    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss");
47    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata");
48    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata");
49    AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss");
50    AddDirectiveHandler<
51      &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel");
52    AddDirectiveHandler<
53      &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro");
54    AddDirectiveHandler<
55      &ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local");
56    AddDirectiveHandler<
57      &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame");
58    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section");
59    AddDirectiveHandler<
60      &ELFAsmParser::ParseDirectivePushSection>(".pushsection");
61    AddDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection");
62    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size");
63    AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous");
64    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type");
65    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident");
66    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver");
67    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref");
68    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
69    AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local");
70    AddDirectiveHandler<
71      &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected");
72    AddDirectiveHandler<
73      &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal");
74    AddDirectiveHandler<
75      &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden");
76  }
77
78  // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
79  // the best way for us to get access to it?
80  bool ParseSectionDirectiveData(StringRef, SMLoc) {
81    return ParseSectionSwitch(".data", ELF::SHT_PROGBITS,
82                              ELF::SHF_WRITE |ELF::SHF_ALLOC,
83                              SectionKind::getDataRel());
84  }
85  bool ParseSectionDirectiveText(StringRef, SMLoc) {
86    return ParseSectionSwitch(".text", ELF::SHT_PROGBITS,
87                              ELF::SHF_EXECINSTR |
88                              ELF::SHF_ALLOC, SectionKind::getText());
89  }
90  bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
91    return ParseSectionSwitch(".bss", ELF::SHT_NOBITS,
92                              ELF::SHF_WRITE |
93                              ELF::SHF_ALLOC, SectionKind::getBSS());
94  }
95  bool ParseSectionDirectiveRoData(StringRef, SMLoc) {
96    return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS,
97                              ELF::SHF_ALLOC,
98                              SectionKind::getReadOnly());
99  }
100  bool ParseSectionDirectiveTData(StringRef, SMLoc) {
101    return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS,
102                              ELF::SHF_ALLOC |
103                              ELF::SHF_TLS | ELF::SHF_WRITE,
104                              SectionKind::getThreadData());
105  }
106  bool ParseSectionDirectiveTBSS(StringRef, SMLoc) {
107    return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS,
108                              ELF::SHF_ALLOC |
109                              ELF::SHF_TLS | ELF::SHF_WRITE,
110                              SectionKind::getThreadBSS());
111  }
112  bool ParseSectionDirectiveDataRel(StringRef, SMLoc) {
113    return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS,
114                              ELF::SHF_ALLOC |
115                              ELF::SHF_WRITE,
116                              SectionKind::getDataRel());
117  }
118  bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) {
119    return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS,
120                              ELF::SHF_ALLOC |
121                              ELF::SHF_WRITE,
122                              SectionKind::getReadOnlyWithRel());
123  }
124  bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) {
125    return ParseSectionSwitch(".data.rel.ro.local", ELF::SHT_PROGBITS,
126                              ELF::SHF_ALLOC |
127                              ELF::SHF_WRITE,
128                              SectionKind::getReadOnlyWithRelLocal());
129  }
130  bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) {
131    return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS,
132                              ELF::SHF_ALLOC |
133                              ELF::SHF_WRITE,
134                              SectionKind::getDataRel());
135  }
136  bool ParseDirectivePushSection(StringRef, SMLoc);
137  bool ParseDirectivePopSection(StringRef, SMLoc);
138  bool ParseDirectiveSection(StringRef, SMLoc);
139  bool ParseDirectiveSize(StringRef, SMLoc);
140  bool ParseDirectivePrevious(StringRef, SMLoc);
141  bool ParseDirectiveType(StringRef, SMLoc);
142  bool ParseDirectiveIdent(StringRef, SMLoc);
143  bool ParseDirectiveSymver(StringRef, SMLoc);
144  bool ParseDirectiveWeakref(StringRef, SMLoc);
145  bool ParseDirectiveSymbolAttribute(StringRef, SMLoc);
146
147private:
148  bool ParseSectionName(StringRef &SectionName);
149};
150
151}
152
153/// ParseDirectiveSymbolAttribute
154///  ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ]
155bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
156  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
157    .Case(".weak", MCSA_Weak)
158    .Case(".local", MCSA_Local)
159    .Case(".hidden", MCSA_Hidden)
160    .Case(".internal", MCSA_Internal)
161    .Case(".protected", MCSA_Protected)
162    .Default(MCSA_Invalid);
163  assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
164  if (getLexer().isNot(AsmToken::EndOfStatement)) {
165    for (;;) {
166      StringRef Name;
167
168      if (getParser().ParseIdentifier(Name))
169        return TokError("expected identifier in directive");
170
171      MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
172
173      getStreamer().EmitSymbolAttribute(Sym, Attr);
174
175      if (getLexer().is(AsmToken::EndOfStatement))
176        break;
177
178      if (getLexer().isNot(AsmToken::Comma))
179        return TokError("unexpected token in directive");
180      Lex();
181    }
182  }
183
184  Lex();
185  return false;
186}
187
188bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type,
189                                      unsigned Flags, SectionKind Kind) {
190  if (getLexer().isNot(AsmToken::EndOfStatement))
191    return TokError("unexpected token in section switching directive");
192  Lex();
193
194  getStreamer().SwitchSection(getContext().getELFSection(
195                                Section, Type, Flags, Kind));
196
197  return false;
198}
199
200bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) {
201  StringRef Name;
202  if (getParser().ParseIdentifier(Name))
203    return TokError("expected identifier in directive");
204  MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);;
205
206  if (getLexer().isNot(AsmToken::Comma))
207    return TokError("unexpected token in directive");
208  Lex();
209
210  const MCExpr *Expr;
211  if (getParser().ParseExpression(Expr))
212    return true;
213
214  if (getLexer().isNot(AsmToken::EndOfStatement))
215    return TokError("unexpected token in directive");
216
217  getStreamer().EmitELFSize(Sym, Expr);
218  return false;
219}
220
221bool ELFAsmParser::ParseSectionName(StringRef &SectionName) {
222  // A section name can contain -, so we cannot just use
223  // ParseIdentifier.
224  SMLoc FirstLoc = getLexer().getLoc();
225  unsigned Size = 0;
226
227  if (getLexer().is(AsmToken::String)) {
228    SectionName = getTok().getIdentifier();
229    Lex();
230    return false;
231  }
232
233  for (;;) {
234    StringRef Tmp;
235    unsigned CurSize;
236
237    SMLoc PrevLoc = getLexer().getLoc();
238    if (getLexer().is(AsmToken::Minus)) {
239      CurSize = 1;
240      Lex(); // Consume the "-".
241    } else if (getLexer().is(AsmToken::String)) {
242      CurSize = getTok().getIdentifier().size() + 2;
243      Lex();
244    } else if (getLexer().is(AsmToken::Identifier)) {
245      CurSize = getTok().getIdentifier().size();
246      Lex();
247    } else {
248      break;
249    }
250
251    Size += CurSize;
252    SectionName = StringRef(FirstLoc.getPointer(), Size);
253
254    // Make sure the following token is adjacent.
255    if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer())
256      break;
257  }
258  if (Size == 0)
259    return true;
260
261  return false;
262}
263
264static SectionKind computeSectionKind(unsigned Flags) {
265  if (Flags & ELF::SHF_EXECINSTR)
266    return SectionKind::getText();
267  if (Flags & ELF::SHF_TLS)
268    return SectionKind::getThreadData();
269  return SectionKind::getDataRel();
270}
271
272static int parseSectionFlags(StringRef flagsStr) {
273  int flags = 0;
274
275  for (unsigned i = 0; i < flagsStr.size(); i++) {
276    switch (flagsStr[i]) {
277    case 'a':
278      flags |= ELF::SHF_ALLOC;
279      break;
280    case 'x':
281      flags |= ELF::SHF_EXECINSTR;
282      break;
283    case 'w':
284      flags |= ELF::SHF_WRITE;
285      break;
286    case 'M':
287      flags |= ELF::SHF_MERGE;
288      break;
289    case 'S':
290      flags |= ELF::SHF_STRINGS;
291      break;
292    case 'T':
293      flags |= ELF::SHF_TLS;
294      break;
295    case 'c':
296      flags |= ELF::XCORE_SHF_CP_SECTION;
297      break;
298    case 'd':
299      flags |= ELF::XCORE_SHF_DP_SECTION;
300      break;
301    case 'G':
302      flags |= ELF::SHF_GROUP;
303      break;
304    default:
305      return -1;
306    }
307  }
308
309  return flags;
310}
311
312bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) {
313  getStreamer().PushSection();
314
315  if (ParseDirectiveSection(s, loc)) {
316    getStreamer().PopSection();
317    return true;
318  }
319
320  return false;
321}
322
323bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) {
324  if (!getStreamer().PopSection())
325    return TokError(".popsection without corresponding .pushsection");
326  return false;
327}
328
329// FIXME: This is a work in progress.
330bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
331  StringRef SectionName;
332
333  if (ParseSectionName(SectionName))
334    return TokError("expected identifier in directive");
335
336  StringRef TypeName;
337  int64_t Size = 0;
338  StringRef GroupName;
339  unsigned Flags = 0;
340
341  // Set the defaults first.
342  if (SectionName == ".fini" || SectionName == ".init" ||
343      SectionName == ".rodata")
344    Flags |= ELF::SHF_ALLOC;
345  if (SectionName == ".fini" || SectionName == ".init")
346    Flags |= ELF::SHF_EXECINSTR;
347
348  if (getLexer().is(AsmToken::Comma)) {
349    Lex();
350
351    if (getLexer().isNot(AsmToken::String))
352      return TokError("expected string in directive");
353
354    StringRef FlagsStr = getTok().getStringContents();
355    Lex();
356
357    int extraFlags = parseSectionFlags(FlagsStr);
358    if (extraFlags < 0)
359      return TokError("unknown flag");
360    Flags |= extraFlags;
361
362    bool Mergeable = Flags & ELF::SHF_MERGE;
363    bool Group = Flags & ELF::SHF_GROUP;
364
365    if (getLexer().isNot(AsmToken::Comma)) {
366      if (Mergeable)
367        return TokError("Mergeable section must specify the type");
368      if (Group)
369        return TokError("Group section must specify the type");
370    } else {
371      Lex();
372      if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At))
373        return TokError("expected '@' or '%' before type");
374
375      Lex();
376      if (getParser().ParseIdentifier(TypeName))
377        return TokError("expected identifier in directive");
378
379      if (Mergeable) {
380        if (getLexer().isNot(AsmToken::Comma))
381          return TokError("expected the entry size");
382        Lex();
383        if (getParser().ParseAbsoluteExpression(Size))
384          return true;
385        if (Size <= 0)
386          return TokError("entry size must be positive");
387      }
388
389      if (Group) {
390        if (getLexer().isNot(AsmToken::Comma))
391          return TokError("expected group name");
392        Lex();
393        if (getParser().ParseIdentifier(GroupName))
394          return true;
395        if (getLexer().is(AsmToken::Comma)) {
396          Lex();
397          StringRef Linkage;
398          if (getParser().ParseIdentifier(Linkage))
399            return true;
400          if (Linkage != "comdat")
401            return TokError("Linkage must be 'comdat'");
402        }
403      }
404    }
405  }
406
407  if (getLexer().isNot(AsmToken::EndOfStatement))
408    return TokError("unexpected token in directive");
409
410  unsigned Type = ELF::SHT_PROGBITS;
411
412  if (!TypeName.empty()) {
413    if (TypeName == "init_array")
414      Type = ELF::SHT_INIT_ARRAY;
415    else if (TypeName == "fini_array")
416      Type = ELF::SHT_FINI_ARRAY;
417    else if (TypeName == "preinit_array")
418      Type = ELF::SHT_PREINIT_ARRAY;
419    else if (TypeName == "nobits")
420      Type = ELF::SHT_NOBITS;
421    else if (TypeName == "progbits")
422      Type = ELF::SHT_PROGBITS;
423    else if (TypeName == "note")
424      Type = ELF::SHT_NOTE;
425    else if (TypeName == "unwind")
426      Type = ELF::SHT_X86_64_UNWIND;
427    else
428      return TokError("unknown section type");
429  }
430
431  SectionKind Kind = computeSectionKind(Flags);
432  getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type,
433                                                         Flags, Kind, Size,
434                                                         GroupName));
435  return false;
436}
437
438bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) {
439  const MCSection *PreviousSection = getStreamer().getPreviousSection();
440  if (PreviousSection == NULL)
441      return TokError(".previous without corresponding .section");
442  getStreamer().SwitchSection(PreviousSection);
443
444  return false;
445}
446
447/// ParseDirectiveELFType
448///  ::= .type identifier , @attribute
449bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
450  StringRef Name;
451  if (getParser().ParseIdentifier(Name))
452    return TokError("expected identifier in directive");
453
454  // Handle the identifier as the key symbol.
455  MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
456
457  if (getLexer().isNot(AsmToken::Comma))
458    return TokError("unexpected token in '.type' directive");
459  Lex();
460
461  if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At))
462    return TokError("expected '@' or '%' before type");
463  Lex();
464
465  StringRef Type;
466  SMLoc TypeLoc;
467
468  TypeLoc = getLexer().getLoc();
469  if (getParser().ParseIdentifier(Type))
470    return TokError("expected symbol type in directive");
471
472  MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Type)
473    .Case("function", MCSA_ELF_TypeFunction)
474    .Case("object", MCSA_ELF_TypeObject)
475    .Case("tls_object", MCSA_ELF_TypeTLS)
476    .Case("common", MCSA_ELF_TypeCommon)
477    .Case("notype", MCSA_ELF_TypeNoType)
478    .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject)
479    .Default(MCSA_Invalid);
480
481  if (Attr == MCSA_Invalid)
482    return Error(TypeLoc, "unsupported attribute in '.type' directive");
483
484  if (getLexer().isNot(AsmToken::EndOfStatement))
485    return TokError("unexpected token in '.type' directive");
486
487  Lex();
488
489  getStreamer().EmitSymbolAttribute(Sym, Attr);
490
491  return false;
492}
493
494/// ParseDirectiveIdent
495///  ::= .ident string
496bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) {
497  if (getLexer().isNot(AsmToken::String))
498    return TokError("unexpected token in '.ident' directive");
499
500  StringRef Data = getTok().getIdentifier();
501
502  Lex();
503
504  const MCSection *Comment =
505    getContext().getELFSection(".comment", ELF::SHT_PROGBITS,
506                               ELF::SHF_MERGE |
507                               ELF::SHF_STRINGS,
508                               SectionKind::getReadOnly(),
509                               1, "");
510
511  getStreamer().PushSection();
512  getStreamer().SwitchSection(Comment);
513  if (!SeenIdent) {
514    getStreamer().EmitIntValue(0, 1);
515    SeenIdent = true;
516  }
517  getStreamer().EmitBytes(Data, 0);
518  getStreamer().EmitIntValue(0, 1);
519  getStreamer().PopSection();
520  return false;
521}
522
523/// ParseDirectiveSymver
524///  ::= .symver foo, bar2@zed
525bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) {
526  StringRef Name;
527  if (getParser().ParseIdentifier(Name))
528    return TokError("expected identifier in directive");
529
530  if (getLexer().isNot(AsmToken::Comma))
531    return TokError("expected a comma");
532
533  Lex();
534
535  StringRef AliasName;
536  if (getParser().ParseIdentifier(AliasName))
537    return TokError("expected identifier in directive");
538
539  if (AliasName.find('@') == StringRef::npos)
540    return TokError("expected a '@' in the name");
541
542  MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName);
543  MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
544  const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext());
545
546  getStreamer().EmitAssignment(Alias, Value);
547  return false;
548}
549
550/// ParseDirectiveWeakref
551///  ::= .weakref foo, bar
552bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) {
553  // FIXME: Share code with the other alias building directives.
554
555  StringRef AliasName;
556  if (getParser().ParseIdentifier(AliasName))
557    return TokError("expected identifier in directive");
558
559  if (getLexer().isNot(AsmToken::Comma))
560    return TokError("expected a comma");
561
562  Lex();
563
564  StringRef Name;
565  if (getParser().ParseIdentifier(Name))
566    return TokError("expected identifier in directive");
567
568  MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName);
569
570  MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);
571
572  getStreamer().EmitWeakReference(Alias, Sym);
573  return false;
574}
575
576namespace llvm {
577
578MCAsmParserExtension *createELFAsmParser() {
579  return new ELFAsmParser;
580}
581
582}
583