Add some more handlers for ELF section directives.
[oota-llvm.git] / lib / MC / MCParser / ELFAsmParser.cpp
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/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/MCSectionELF.h"
16 #include "llvm/MC/MCStreamer.h"
17 #include "llvm/ADT/Twine.h"
18 using namespace llvm;
19
20 namespace {
21
22 class ELFAsmParser : public MCAsmParserExtension {
23   template<bool (ELFAsmParser::*Handler)(StringRef, SMLoc)>
24   void AddDirectiveHandler(StringRef Directive) {
25     getParser().AddDirectiveHandler(this, Directive,
26                                     HandleDirective<ELFAsmParser, Handler>);
27   }
28
29   bool ParseSectionSwitch(StringRef Section, unsigned Type,
30                           unsigned Flags, SectionKind Kind);
31
32 public:
33   ELFAsmParser() {}
34
35   virtual void Initialize(MCAsmParser &Parser) {
36     // Call the base implementation.
37     this->MCAsmParserExtension::Initialize(Parser);
38
39     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data");
40     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text");
41     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss");
42     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata");
43     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata");
44     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss");
45     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel");
46     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro");
47     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local");
48     AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame");
49     AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section");
50     AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size");
51     AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128");
52     AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128");
53   }
54
55   bool ParseSectionDirectiveData(StringRef, SMLoc) {
56     return ParseSectionSwitch(".data", MCSectionELF::SHT_PROGBITS,
57                               MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC,
58                               SectionKind::getDataRel());
59   }
60   bool ParseSectionDirectiveText(StringRef, SMLoc) {
61     return ParseSectionSwitch(".text", MCSectionELF::SHT_PROGBITS,
62                               MCSectionELF::SHF_EXECINSTR |
63                               MCSectionELF::SHF_ALLOC, SectionKind::getText());
64   }
65   bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
66     return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS,
67                               MCSectionELF::SHF_WRITE |
68                               MCSectionELF::SHF_ALLOC, SectionKind::getBSS());
69   }
70   bool ParseSectionDirectiveRoData(StringRef, SMLoc) {
71     return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS,
72                               MCSectionELF::SHF_ALLOC,
73                               SectionKind::getReadOnly());
74   }
75   bool ParseSectionDirectiveTData(StringRef, SMLoc) {
76     return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS,
77                               MCSectionELF::SHF_ALLOC |
78                               MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE,
79                               SectionKind::getThreadData());
80   }
81   bool ParseSectionDirectiveTBSS(StringRef, SMLoc) {
82     return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS,
83                               MCSectionELF::SHF_ALLOC |
84                               MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE,
85                               SectionKind::getThreadBSS());
86   }
87   bool ParseSectionDirectiveDataRel(StringRef, SMLoc) {
88     return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS,
89                               MCSectionELF::SHF_ALLOC |
90                               MCSectionELF::SHF_WRITE,
91                               SectionKind::getDataRel());
92   }
93   bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) {
94     return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS,
95                               MCSectionELF::SHF_ALLOC |
96                               MCSectionELF::SHF_WRITE,
97                               SectionKind::getReadOnlyWithRel());
98   }
99   bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) {
100     return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS,
101                               MCSectionELF::SHF_ALLOC |
102                               MCSectionELF::SHF_WRITE,
103                               SectionKind::getReadOnlyWithRelLocal());
104   }
105   bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) {
106     return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS,
107                               MCSectionELF::SHF_ALLOC |
108                               MCSectionELF::SHF_WRITE,
109                               SectionKind::getDataRel());
110   }
111   bool ParseDirectiveLEB128(StringRef, SMLoc);
112   bool ParseDirectiveSection(StringRef, SMLoc);
113   bool ParseDirectiveSize(StringRef, SMLoc);
114 };
115
116 }
117
118 bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type,
119                                       unsigned Flags, SectionKind Kind) {
120   if (getLexer().isNot(AsmToken::EndOfStatement))
121     return TokError("unexpected token in section switching directive");
122   Lex();
123
124   getStreamer().SwitchSection(getContext().getELFSection(
125                                 Section, Type, Flags, Kind));
126
127   return false;
128 }
129
130 bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) {
131   StringRef Name;
132   if (getParser().ParseIdentifier(Name))
133     return TokError("expected identifier in directive");
134   MCSymbol *Sym = getContext().GetOrCreateSymbol(Name);;
135
136   if (getLexer().isNot(AsmToken::Comma))
137     return TokError("unexpected token in directive");
138   Lex();
139
140   const MCExpr *Expr;
141   if (getParser().ParseExpression(Expr))
142     return true;
143
144   if (getLexer().isNot(AsmToken::EndOfStatement))
145     return TokError("unexpected token in directive");
146
147   getStreamer().EmitELFSize(Sym, Expr);
148   return false;
149 }
150
151 // FIXME: This is a work in progress.
152 bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
153   StringRef SectionName;
154   // FIXME: This doesn't parse section names like ".note.GNU-stack" correctly.
155   if (getParser().ParseIdentifier(SectionName))
156     return TokError("expected identifier in directive");
157
158   std::string FlagsStr;
159   StringRef TypeName;
160   int64_t Size = 0;
161   if (getLexer().is(AsmToken::Comma)) {
162     Lex();
163
164     if (getLexer().isNot(AsmToken::String))
165       return TokError("expected string in directive");
166
167     FlagsStr = getTok().getStringContents();
168     Lex();
169
170     AsmToken::TokenKind TypeStartToken;
171     if (getContext().getAsmInfo().getCommentString()[0] == '@')
172       TypeStartToken = AsmToken::Percent;
173     else
174       TypeStartToken = AsmToken::At;
175
176     if (getLexer().is(AsmToken::Comma)) {
177       Lex();
178       if (getLexer().is(TypeStartToken)) {
179         Lex();
180         if (getParser().ParseIdentifier(TypeName))
181           return TokError("expected identifier in directive");
182
183         if (getLexer().is(AsmToken::Comma)) {
184           Lex();
185
186           if (getParser().ParseAbsoluteExpression(Size))
187             return true;
188
189           if (Size <= 0)
190             return TokError("section size must be positive");
191         }
192       }
193     }
194   }
195
196   if (getLexer().isNot(AsmToken::EndOfStatement))
197     return TokError("unexpected token in directive");
198
199   unsigned Flags = 0;
200   for (unsigned i = 0; i < FlagsStr.size(); i++) {
201     switch (FlagsStr[i]) {
202     case 'a':
203       Flags |= MCSectionELF::SHF_ALLOC;
204       break;
205     case 'x':
206       Flags |= MCSectionELF::SHF_EXECINSTR;
207       break;
208     case 'w':
209       Flags |= MCSectionELF::SHF_WRITE;
210       break;
211     case 'M':
212       Flags |= MCSectionELF::SHF_MERGE;
213       break;
214     case 'S':
215       Flags |= MCSectionELF::SHF_STRINGS;
216       break;
217     case 'T':
218       Flags |= MCSectionELF::SHF_TLS;
219       break;
220     case 'c':
221       Flags |= MCSectionELF::XCORE_SHF_CP_SECTION;
222       break;
223     case 'd':
224       Flags |= MCSectionELF::XCORE_SHF_DP_SECTION;
225       break;
226     default:
227       return TokError("unknown flag");
228     }
229   }
230
231   unsigned Type = MCSectionELF::SHT_NULL;
232   if (!TypeName.empty()) {
233     if (TypeName == "init_array")
234       Type = MCSectionELF::SHT_INIT_ARRAY;
235     else if (TypeName == "fini_array")
236       Type = MCSectionELF::SHT_FINI_ARRAY;
237     else if (TypeName == "preinit_array")
238       Type = MCSectionELF::SHT_PREINIT_ARRAY;
239     else if (TypeName == "nobits")
240       Type = MCSectionELF::SHT_NOBITS;
241     else if (TypeName == "progbits")
242       Type = MCSectionELF::SHT_PROGBITS;
243     else
244       return TokError("unknown section type");
245   }
246
247   SectionKind Kind = (Flags & MCSectionELF::SHF_EXECINSTR)
248                      ? SectionKind::getText()
249                      : SectionKind::getDataRel();
250   getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type,
251                                                          Flags, Kind, false));
252   return false;
253 }
254
255 bool ELFAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) {
256   int64_t Value;
257   if (getParser().ParseAbsoluteExpression(Value))
258     return true;
259
260   if (getLexer().isNot(AsmToken::EndOfStatement))
261     return TokError("unexpected token in directive");
262
263   // FIXME: Add proper MC support.
264   if (getContext().getAsmInfo().hasLEB128()) {
265     if (DirName[1] == 's')
266       getStreamer().EmitRawText("\t.sleb128\t" + Twine(Value));
267     else
268       getStreamer().EmitRawText("\t.uleb128\t" + Twine(Value));
269     return false;
270   }
271   // FIXME: This shouldn't be an error!
272   return TokError("LEB128 not supported yet");
273 }
274
275 namespace llvm {
276
277 MCAsmParserExtension *createELFAsmParser() {
278   return new ELFAsmParser;
279 }
280
281 }