]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
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" | |
1a4d82fc | 19 | #include "llvm/MC/MCSymbol.h" |
223e47cc LB |
20 | #include "llvm/Support/ELF.h" |
21 | using namespace llvm; | |
22 | ||
23 | namespace { | |
24 | ||
25 | class ELFAsmParser : public MCAsmParserExtension { | |
970d7e83 LB |
26 | template<bool (ELFAsmParser::*HandlerMethod)(StringRef, SMLoc)> |
27 | void addDirectiveHandler(StringRef Directive) { | |
28 | MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair( | |
29 | this, HandleDirective<ELFAsmParser, HandlerMethod>); | |
30 | ||
31 | getParser().addDirectiveHandler(Directive, Handler); | |
223e47cc LB |
32 | } |
33 | ||
1a4d82fc JJ |
34 | bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, |
35 | SectionKind Kind); | |
223e47cc LB |
36 | |
37 | public: | |
1a4d82fc | 38 | ELFAsmParser() { BracketExpressionsSupported = true; } |
223e47cc | 39 | |
1a4d82fc | 40 | void Initialize(MCAsmParser &Parser) override { |
223e47cc LB |
41 | // Call the base implementation. |
42 | this->MCAsmParserExtension::Initialize(Parser); | |
43 | ||
970d7e83 LB |
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< | |
223e47cc | 51 | &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel"); |
970d7e83 | 52 | addDirectiveHandler< |
223e47cc | 53 | &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro"); |
970d7e83 | 54 | addDirectiveHandler< |
223e47cc | 55 | &ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local"); |
970d7e83 | 56 | addDirectiveHandler< |
223e47cc | 57 | &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); |
970d7e83 LB |
58 | addDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); |
59 | addDirectiveHandler< | |
223e47cc | 60 | &ELFAsmParser::ParseDirectivePushSection>(".pushsection"); |
970d7e83 LB |
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::ParseDirectiveVersion>(".version"); | |
68 | addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); | |
69 | addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); | |
70 | addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local"); | |
71 | addDirectiveHandler< | |
223e47cc | 72 | &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected"); |
970d7e83 | 73 | addDirectiveHandler< |
223e47cc | 74 | &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal"); |
970d7e83 | 75 | addDirectiveHandler< |
223e47cc | 76 | &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden"); |
1a4d82fc | 77 | addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection"); |
223e47cc LB |
78 | } |
79 | ||
80 | // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is | |
81 | // the best way for us to get access to it? | |
82 | bool ParseSectionDirectiveData(StringRef, SMLoc) { | |
83 | return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, | |
84 | ELF::SHF_WRITE |ELF::SHF_ALLOC, | |
85 | SectionKind::getDataRel()); | |
86 | } | |
87 | bool ParseSectionDirectiveText(StringRef, SMLoc) { | |
88 | return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, | |
89 | ELF::SHF_EXECINSTR | | |
90 | ELF::SHF_ALLOC, SectionKind::getText()); | |
91 | } | |
92 | bool ParseSectionDirectiveBSS(StringRef, SMLoc) { | |
93 | return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, | |
94 | ELF::SHF_WRITE | | |
95 | ELF::SHF_ALLOC, SectionKind::getBSS()); | |
96 | } | |
97 | bool ParseSectionDirectiveRoData(StringRef, SMLoc) { | |
98 | return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, | |
99 | ELF::SHF_ALLOC, | |
100 | SectionKind::getReadOnly()); | |
101 | } | |
102 | bool ParseSectionDirectiveTData(StringRef, SMLoc) { | |
103 | return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, | |
104 | ELF::SHF_ALLOC | | |
105 | ELF::SHF_TLS | ELF::SHF_WRITE, | |
106 | SectionKind::getThreadData()); | |
107 | } | |
108 | bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { | |
109 | return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, | |
110 | ELF::SHF_ALLOC | | |
111 | ELF::SHF_TLS | ELF::SHF_WRITE, | |
112 | SectionKind::getThreadBSS()); | |
113 | } | |
114 | bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { | |
115 | return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, | |
116 | ELF::SHF_ALLOC | | |
117 | ELF::SHF_WRITE, | |
118 | SectionKind::getDataRel()); | |
119 | } | |
120 | bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { | |
121 | return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, | |
122 | ELF::SHF_ALLOC | | |
123 | ELF::SHF_WRITE, | |
124 | SectionKind::getReadOnlyWithRel()); | |
125 | } | |
126 | bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { | |
127 | return ParseSectionSwitch(".data.rel.ro.local", ELF::SHT_PROGBITS, | |
128 | ELF::SHF_ALLOC | | |
129 | ELF::SHF_WRITE, | |
130 | SectionKind::getReadOnlyWithRelLocal()); | |
131 | } | |
132 | bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { | |
133 | return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, | |
134 | ELF::SHF_ALLOC | | |
135 | ELF::SHF_WRITE, | |
136 | SectionKind::getDataRel()); | |
137 | } | |
138 | bool ParseDirectivePushSection(StringRef, SMLoc); | |
139 | bool ParseDirectivePopSection(StringRef, SMLoc); | |
140 | bool ParseDirectiveSection(StringRef, SMLoc); | |
141 | bool ParseDirectiveSize(StringRef, SMLoc); | |
142 | bool ParseDirectivePrevious(StringRef, SMLoc); | |
143 | bool ParseDirectiveType(StringRef, SMLoc); | |
144 | bool ParseDirectiveIdent(StringRef, SMLoc); | |
145 | bool ParseDirectiveSymver(StringRef, SMLoc); | |
146 | bool ParseDirectiveVersion(StringRef, SMLoc); | |
147 | bool ParseDirectiveWeakref(StringRef, SMLoc); | |
148 | bool ParseDirectiveSymbolAttribute(StringRef, SMLoc); | |
1a4d82fc | 149 | bool ParseDirectiveSubsection(StringRef, SMLoc); |
223e47cc LB |
150 | |
151 | private: | |
152 | bool ParseSectionName(StringRef &SectionName); | |
1a4d82fc JJ |
153 | bool ParseSectionArguments(bool IsPush, SMLoc loc); |
154 | unsigned parseSunStyleSectionFlags(); | |
223e47cc LB |
155 | }; |
156 | ||
157 | } | |
158 | ||
159 | /// ParseDirectiveSymbolAttribute | |
160 | /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ] | |
161 | bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { | |
162 | MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive) | |
163 | .Case(".weak", MCSA_Weak) | |
164 | .Case(".local", MCSA_Local) | |
165 | .Case(".hidden", MCSA_Hidden) | |
166 | .Case(".internal", MCSA_Internal) | |
167 | .Case(".protected", MCSA_Protected) | |
168 | .Default(MCSA_Invalid); | |
169 | assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!"); | |
170 | if (getLexer().isNot(AsmToken::EndOfStatement)) { | |
171 | for (;;) { | |
172 | StringRef Name; | |
173 | ||
970d7e83 | 174 | if (getParser().parseIdentifier(Name)) |
223e47cc LB |
175 | return TokError("expected identifier in directive"); |
176 | ||
177 | MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); | |
178 | ||
179 | getStreamer().EmitSymbolAttribute(Sym, Attr); | |
180 | ||
181 | if (getLexer().is(AsmToken::EndOfStatement)) | |
182 | break; | |
183 | ||
184 | if (getLexer().isNot(AsmToken::Comma)) | |
185 | return TokError("unexpected token in directive"); | |
186 | Lex(); | |
187 | } | |
188 | } | |
189 | ||
190 | Lex(); | |
191 | return false; | |
192 | } | |
193 | ||
194 | bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, | |
195 | unsigned Flags, SectionKind Kind) { | |
1a4d82fc JJ |
196 | const MCExpr *Subsection = nullptr; |
197 | if (getLexer().isNot(AsmToken::EndOfStatement)) { | |
198 | if (getParser().parseExpression(Subsection)) | |
199 | return true; | |
200 | } | |
223e47cc LB |
201 | |
202 | getStreamer().SwitchSection(getContext().getELFSection( | |
1a4d82fc JJ |
203 | Section, Type, Flags, Kind), |
204 | Subsection); | |
223e47cc LB |
205 | |
206 | return false; | |
207 | } | |
208 | ||
209 | bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { | |
210 | StringRef Name; | |
970d7e83 | 211 | if (getParser().parseIdentifier(Name)) |
223e47cc LB |
212 | return TokError("expected identifier in directive"); |
213 | MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); | |
214 | ||
215 | if (getLexer().isNot(AsmToken::Comma)) | |
216 | return TokError("unexpected token in directive"); | |
217 | Lex(); | |
218 | ||
219 | const MCExpr *Expr; | |
970d7e83 | 220 | if (getParser().parseExpression(Expr)) |
223e47cc LB |
221 | return true; |
222 | ||
223 | if (getLexer().isNot(AsmToken::EndOfStatement)) | |
224 | return TokError("unexpected token in directive"); | |
225 | ||
226 | getStreamer().EmitELFSize(Sym, Expr); | |
227 | return false; | |
228 | } | |
229 | ||
230 | bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { | |
231 | // A section name can contain -, so we cannot just use | |
970d7e83 | 232 | // parseIdentifier. |
223e47cc LB |
233 | SMLoc FirstLoc = getLexer().getLoc(); |
234 | unsigned Size = 0; | |
235 | ||
236 | if (getLexer().is(AsmToken::String)) { | |
237 | SectionName = getTok().getIdentifier(); | |
238 | Lex(); | |
239 | return false; | |
240 | } | |
241 | ||
242 | for (;;) { | |
223e47cc LB |
243 | unsigned CurSize; |
244 | ||
245 | SMLoc PrevLoc = getLexer().getLoc(); | |
246 | if (getLexer().is(AsmToken::Minus)) { | |
247 | CurSize = 1; | |
248 | Lex(); // Consume the "-". | |
249 | } else if (getLexer().is(AsmToken::String)) { | |
250 | CurSize = getTok().getIdentifier().size() + 2; | |
251 | Lex(); | |
252 | } else if (getLexer().is(AsmToken::Identifier)) { | |
253 | CurSize = getTok().getIdentifier().size(); | |
254 | Lex(); | |
255 | } else { | |
256 | break; | |
257 | } | |
258 | ||
259 | Size += CurSize; | |
260 | SectionName = StringRef(FirstLoc.getPointer(), Size); | |
261 | ||
262 | // Make sure the following token is adjacent. | |
263 | if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) | |
264 | break; | |
265 | } | |
266 | if (Size == 0) | |
267 | return true; | |
268 | ||
269 | return false; | |
270 | } | |
271 | ||
1a4d82fc | 272 | static SectionKind computeSectionKind(unsigned Flags, unsigned ElemSize) { |
223e47cc LB |
273 | if (Flags & ELF::SHF_EXECINSTR) |
274 | return SectionKind::getText(); | |
275 | if (Flags & ELF::SHF_TLS) | |
276 | return SectionKind::getThreadData(); | |
1a4d82fc JJ |
277 | if (Flags & ELF::SHF_MERGE) { |
278 | if (Flags & ELF::SHF_STRINGS) { | |
279 | switch (ElemSize) { | |
280 | default: | |
281 | break; | |
282 | case 1: | |
283 | return SectionKind::getMergeable1ByteCString(); | |
284 | case 2: | |
285 | return SectionKind::getMergeable2ByteCString(); | |
286 | case 4: | |
287 | return SectionKind::getMergeable4ByteCString(); | |
288 | } | |
289 | } else { | |
290 | switch (ElemSize) { | |
291 | default: | |
292 | break; | |
293 | case 4: | |
294 | return SectionKind::getMergeableConst4(); | |
295 | case 8: | |
296 | return SectionKind::getMergeableConst8(); | |
297 | case 16: | |
298 | return SectionKind::getMergeableConst16(); | |
299 | } | |
300 | } | |
301 | } | |
302 | ||
223e47cc LB |
303 | return SectionKind::getDataRel(); |
304 | } | |
305 | ||
1a4d82fc JJ |
306 | static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { |
307 | unsigned flags = 0; | |
223e47cc LB |
308 | |
309 | for (unsigned i = 0; i < flagsStr.size(); i++) { | |
310 | switch (flagsStr[i]) { | |
311 | case 'a': | |
312 | flags |= ELF::SHF_ALLOC; | |
313 | break; | |
1a4d82fc JJ |
314 | case 'e': |
315 | flags |= ELF::SHF_EXCLUDE; | |
316 | break; | |
223e47cc LB |
317 | case 'x': |
318 | flags |= ELF::SHF_EXECINSTR; | |
319 | break; | |
320 | case 'w': | |
321 | flags |= ELF::SHF_WRITE; | |
322 | break; | |
323 | case 'M': | |
324 | flags |= ELF::SHF_MERGE; | |
325 | break; | |
326 | case 'S': | |
327 | flags |= ELF::SHF_STRINGS; | |
328 | break; | |
329 | case 'T': | |
330 | flags |= ELF::SHF_TLS; | |
331 | break; | |
332 | case 'c': | |
333 | flags |= ELF::XCORE_SHF_CP_SECTION; | |
334 | break; | |
335 | case 'd': | |
336 | flags |= ELF::XCORE_SHF_DP_SECTION; | |
337 | break; | |
338 | case 'G': | |
339 | flags |= ELF::SHF_GROUP; | |
340 | break; | |
1a4d82fc JJ |
341 | case '?': |
342 | *UseLastGroup = true; | |
343 | break; | |
223e47cc | 344 | default: |
1a4d82fc | 345 | return -1U; |
223e47cc LB |
346 | } |
347 | } | |
348 | ||
349 | return flags; | |
350 | } | |
351 | ||
1a4d82fc JJ |
352 | unsigned ELFAsmParser::parseSunStyleSectionFlags() { |
353 | unsigned flags = 0; | |
354 | while (getLexer().is(AsmToken::Hash)) { | |
355 | Lex(); // Eat the #. | |
356 | ||
357 | if (!getLexer().is(AsmToken::Identifier)) | |
358 | return -1U; | |
359 | ||
360 | StringRef flagId = getTok().getIdentifier(); | |
361 | if (flagId == "alloc") | |
362 | flags |= ELF::SHF_ALLOC; | |
363 | else if (flagId == "execinstr") | |
364 | flags |= ELF::SHF_EXECINSTR; | |
365 | else if (flagId == "write") | |
366 | flags |= ELF::SHF_WRITE; | |
367 | else if (flagId == "tls") | |
368 | flags |= ELF::SHF_TLS; | |
369 | else | |
370 | return -1U; | |
371 | ||
372 | Lex(); // Eat the flag. | |
373 | ||
374 | if (!getLexer().is(AsmToken::Comma)) | |
375 | break; | |
376 | Lex(); // Eat the comma. | |
377 | } | |
378 | return flags; | |
379 | } | |
380 | ||
381 | ||
223e47cc LB |
382 | bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { |
383 | getStreamer().PushSection(); | |
384 | ||
1a4d82fc | 385 | if (ParseSectionArguments(/*IsPush=*/true, loc)) { |
223e47cc LB |
386 | getStreamer().PopSection(); |
387 | return true; | |
388 | } | |
389 | ||
390 | return false; | |
391 | } | |
392 | ||
393 | bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { | |
394 | if (!getStreamer().PopSection()) | |
395 | return TokError(".popsection without corresponding .pushsection"); | |
396 | return false; | |
397 | } | |
398 | ||
399 | // FIXME: This is a work in progress. | |
1a4d82fc JJ |
400 | bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) { |
401 | return ParseSectionArguments(/*IsPush=*/false, loc); | |
402 | } | |
403 | ||
404 | bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) { | |
223e47cc LB |
405 | StringRef SectionName; |
406 | ||
407 | if (ParseSectionName(SectionName)) | |
408 | return TokError("expected identifier in directive"); | |
409 | ||
410 | StringRef TypeName; | |
411 | int64_t Size = 0; | |
412 | StringRef GroupName; | |
413 | unsigned Flags = 0; | |
1a4d82fc JJ |
414 | const MCExpr *Subsection = nullptr; |
415 | bool UseLastGroup = false; | |
223e47cc LB |
416 | |
417 | // Set the defaults first. | |
418 | if (SectionName == ".fini" || SectionName == ".init" || | |
419 | SectionName == ".rodata") | |
420 | Flags |= ELF::SHF_ALLOC; | |
421 | if (SectionName == ".fini" || SectionName == ".init") | |
422 | Flags |= ELF::SHF_EXECINSTR; | |
423 | ||
424 | if (getLexer().is(AsmToken::Comma)) { | |
425 | Lex(); | |
426 | ||
1a4d82fc JJ |
427 | if (IsPush && getLexer().isNot(AsmToken::String)) { |
428 | if (getParser().parseExpression(Subsection)) | |
429 | return true; | |
430 | if (getLexer().isNot(AsmToken::Comma)) | |
431 | goto EndStmt; | |
432 | Lex(); | |
433 | } | |
223e47cc | 434 | |
1a4d82fc | 435 | unsigned extraFlags; |
223e47cc | 436 | |
1a4d82fc JJ |
437 | if (getLexer().isNot(AsmToken::String)) { |
438 | if (!getContext().getAsmInfo()->usesSunStyleELFSectionSwitchSyntax() | |
439 | || getLexer().isNot(AsmToken::Hash)) | |
440 | return TokError("expected string in directive"); | |
441 | extraFlags = parseSunStyleSectionFlags(); | |
442 | } else { | |
443 | StringRef FlagsStr = getTok().getStringContents(); | |
444 | Lex(); | |
445 | extraFlags = parseSectionFlags(FlagsStr, &UseLastGroup); | |
446 | } | |
447 | ||
448 | if (extraFlags == -1U) | |
223e47cc LB |
449 | return TokError("unknown flag"); |
450 | Flags |= extraFlags; | |
451 | ||
452 | bool Mergeable = Flags & ELF::SHF_MERGE; | |
453 | bool Group = Flags & ELF::SHF_GROUP; | |
1a4d82fc JJ |
454 | if (Group && UseLastGroup) |
455 | return TokError("Section cannot specifiy a group name while also acting " | |
456 | "as a member of the last group"); | |
223e47cc LB |
457 | |
458 | if (getLexer().isNot(AsmToken::Comma)) { | |
459 | if (Mergeable) | |
460 | return TokError("Mergeable section must specify the type"); | |
461 | if (Group) | |
462 | return TokError("Group section must specify the type"); | |
463 | } else { | |
464 | Lex(); | |
1a4d82fc JJ |
465 | if (getLexer().is(AsmToken::At) || getLexer().is(AsmToken::Percent) || |
466 | getLexer().is(AsmToken::String)) { | |
467 | if (!getLexer().is(AsmToken::String)) | |
468 | Lex(); | |
469 | } else | |
470 | return TokError("expected '@<type>', '%<type>' or \"<type>\""); | |
223e47cc | 471 | |
970d7e83 | 472 | if (getParser().parseIdentifier(TypeName)) |
223e47cc LB |
473 | return TokError("expected identifier in directive"); |
474 | ||
475 | if (Mergeable) { | |
476 | if (getLexer().isNot(AsmToken::Comma)) | |
477 | return TokError("expected the entry size"); | |
478 | Lex(); | |
970d7e83 | 479 | if (getParser().parseAbsoluteExpression(Size)) |
223e47cc LB |
480 | return true; |
481 | if (Size <= 0) | |
482 | return TokError("entry size must be positive"); | |
483 | } | |
484 | ||
485 | if (Group) { | |
486 | if (getLexer().isNot(AsmToken::Comma)) | |
487 | return TokError("expected group name"); | |
488 | Lex(); | |
970d7e83 | 489 | if (getParser().parseIdentifier(GroupName)) |
223e47cc LB |
490 | return true; |
491 | if (getLexer().is(AsmToken::Comma)) { | |
492 | Lex(); | |
493 | StringRef Linkage; | |
970d7e83 | 494 | if (getParser().parseIdentifier(Linkage)) |
223e47cc LB |
495 | return true; |
496 | if (Linkage != "comdat") | |
497 | return TokError("Linkage must be 'comdat'"); | |
498 | } | |
499 | } | |
500 | } | |
501 | } | |
502 | ||
1a4d82fc | 503 | EndStmt: |
223e47cc LB |
504 | if (getLexer().isNot(AsmToken::EndOfStatement)) |
505 | return TokError("unexpected token in directive"); | |
506 | ||
507 | unsigned Type = ELF::SHT_PROGBITS; | |
508 | ||
970d7e83 LB |
509 | if (TypeName.empty()) { |
510 | if (SectionName.startswith(".note")) | |
511 | Type = ELF::SHT_NOTE; | |
512 | else if (SectionName == ".init_array") | |
513 | Type = ELF::SHT_INIT_ARRAY; | |
514 | else if (SectionName == ".fini_array") | |
515 | Type = ELF::SHT_FINI_ARRAY; | |
516 | else if (SectionName == ".preinit_array") | |
517 | Type = ELF::SHT_PREINIT_ARRAY; | |
518 | } else { | |
223e47cc LB |
519 | if (TypeName == "init_array") |
520 | Type = ELF::SHT_INIT_ARRAY; | |
521 | else if (TypeName == "fini_array") | |
522 | Type = ELF::SHT_FINI_ARRAY; | |
523 | else if (TypeName == "preinit_array") | |
524 | Type = ELF::SHT_PREINIT_ARRAY; | |
525 | else if (TypeName == "nobits") | |
526 | Type = ELF::SHT_NOBITS; | |
527 | else if (TypeName == "progbits") | |
528 | Type = ELF::SHT_PROGBITS; | |
529 | else if (TypeName == "note") | |
530 | Type = ELF::SHT_NOTE; | |
531 | else if (TypeName == "unwind") | |
532 | Type = ELF::SHT_X86_64_UNWIND; | |
533 | else | |
534 | return TokError("unknown section type"); | |
535 | } | |
536 | ||
1a4d82fc JJ |
537 | if (UseLastGroup) { |
538 | MCSectionSubPair CurrentSection = getStreamer().getCurrentSection(); | |
539 | if (const MCSectionELF *Section = | |
540 | cast_or_null<MCSectionELF>(CurrentSection.first)) | |
541 | if (const MCSymbol *Group = Section->getGroup()) { | |
542 | GroupName = Group->getName(); | |
543 | Flags |= ELF::SHF_GROUP; | |
544 | } | |
545 | } | |
546 | ||
547 | SectionKind Kind = computeSectionKind(Flags, Size); | |
548 | const MCSection *ELFSection = getContext().getELFSection( | |
549 | SectionName, Type, Flags, Kind, Size, GroupName); | |
550 | getStreamer().SwitchSection(ELFSection, Subsection); | |
551 | ||
552 | if (getContext().getGenDwarfForAssembly()) { | |
553 | auto &Sections = getContext().getGenDwarfSectionSyms(); | |
554 | auto InsertResult = Sections.insert( | |
555 | std::make_pair(ELFSection, std::make_pair(nullptr, nullptr))); | |
556 | if (InsertResult.second) { | |
557 | if (getContext().getDwarfVersion() <= 2) | |
558 | Warning(loc, "DWARF2 only supports one section per compilation unit"); | |
559 | ||
560 | MCSymbol *SectionStartSymbol = getContext().CreateTempSymbol(); | |
561 | getStreamer().EmitLabel(SectionStartSymbol); | |
562 | InsertResult.first->second.first = SectionStartSymbol; | |
563 | } | |
564 | } | |
565 | ||
223e47cc LB |
566 | return false; |
567 | } | |
568 | ||
569 | bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { | |
1a4d82fc JJ |
570 | MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); |
571 | if (PreviousSection.first == nullptr) | |
223e47cc | 572 | return TokError(".previous without corresponding .section"); |
1a4d82fc | 573 | getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); |
223e47cc LB |
574 | |
575 | return false; | |
576 | } | |
577 | ||
1a4d82fc JJ |
578 | static MCSymbolAttr MCAttrForString(StringRef Type) { |
579 | return StringSwitch<MCSymbolAttr>(Type) | |
580 | .Cases("STT_FUNC", "function", MCSA_ELF_TypeFunction) | |
581 | .Cases("STT_OBJECT", "object", MCSA_ELF_TypeObject) | |
582 | .Cases("STT_TLS", "tls_object", MCSA_ELF_TypeTLS) | |
583 | .Cases("STT_COMMON", "common", MCSA_ELF_TypeCommon) | |
584 | .Cases("STT_NOTYPE", "notype", MCSA_ELF_TypeNoType) | |
585 | .Cases("STT_GNU_IFUNC", "gnu_indirect_function", | |
586 | MCSA_ELF_TypeIndFunction) | |
587 | .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) | |
588 | .Default(MCSA_Invalid); | |
589 | } | |
590 | ||
223e47cc | 591 | /// ParseDirectiveELFType |
1a4d82fc JJ |
592 | /// ::= .type identifier , STT_<TYPE_IN_UPPER_CASE> |
593 | /// ::= .type identifier , #attribute | |
223e47cc | 594 | /// ::= .type identifier , @attribute |
1a4d82fc JJ |
595 | /// ::= .type identifier , %attribute |
596 | /// ::= .type identifier , "attribute" | |
223e47cc LB |
597 | bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { |
598 | StringRef Name; | |
970d7e83 | 599 | if (getParser().parseIdentifier(Name)) |
223e47cc LB |
600 | return TokError("expected identifier in directive"); |
601 | ||
602 | // Handle the identifier as the key symbol. | |
603 | MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); | |
604 | ||
1a4d82fc JJ |
605 | // NOTE the comma is optional in all cases. It is only documented as being |
606 | // optional in the first case, however, GAS will silently treat the comma as | |
607 | // optional in all cases. Furthermore, although the documentation states that | |
608 | // the first form only accepts STT_<TYPE_IN_UPPER_CASE>, in reality, GAS | |
609 | // accepts both the upper case name as well as the lower case aliases. | |
610 | if (getLexer().is(AsmToken::Comma)) | |
611 | Lex(); | |
223e47cc | 612 | |
1a4d82fc JJ |
613 | if (getLexer().isNot(AsmToken::Identifier) && |
614 | getLexer().isNot(AsmToken::Hash) && getLexer().isNot(AsmToken::At) && | |
615 | getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::String)) | |
616 | return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', '@<type>', " | |
617 | "'%<type>' or \"<type>\""); | |
223e47cc | 618 | |
1a4d82fc JJ |
619 | if (getLexer().isNot(AsmToken::String) && |
620 | getLexer().isNot(AsmToken::Identifier)) | |
621 | Lex(); | |
223e47cc | 622 | |
1a4d82fc JJ |
623 | SMLoc TypeLoc = getLexer().getLoc(); |
624 | ||
625 | StringRef Type; | |
970d7e83 | 626 | if (getParser().parseIdentifier(Type)) |
223e47cc LB |
627 | return TokError("expected symbol type in directive"); |
628 | ||
1a4d82fc | 629 | MCSymbolAttr Attr = MCAttrForString(Type); |
223e47cc LB |
630 | if (Attr == MCSA_Invalid) |
631 | return Error(TypeLoc, "unsupported attribute in '.type' directive"); | |
632 | ||
633 | if (getLexer().isNot(AsmToken::EndOfStatement)) | |
634 | return TokError("unexpected token in '.type' directive"); | |
223e47cc LB |
635 | Lex(); |
636 | ||
637 | getStreamer().EmitSymbolAttribute(Sym, Attr); | |
638 | ||
639 | return false; | |
640 | } | |
641 | ||
642 | /// ParseDirectiveIdent | |
643 | /// ::= .ident string | |
644 | bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { | |
645 | if (getLexer().isNot(AsmToken::String)) | |
646 | return TokError("unexpected token in '.ident' directive"); | |
647 | ||
648 | StringRef Data = getTok().getIdentifier(); | |
649 | ||
650 | Lex(); | |
651 | ||
1a4d82fc | 652 | getStreamer().EmitIdent(Data); |
223e47cc LB |
653 | return false; |
654 | } | |
655 | ||
656 | /// ParseDirectiveSymver | |
657 | /// ::= .symver foo, bar2@zed | |
658 | bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { | |
659 | StringRef Name; | |
970d7e83 | 660 | if (getParser().parseIdentifier(Name)) |
223e47cc LB |
661 | return TokError("expected identifier in directive"); |
662 | ||
663 | if (getLexer().isNot(AsmToken::Comma)) | |
664 | return TokError("expected a comma"); | |
665 | ||
1a4d82fc JJ |
666 | // ARM assembly uses @ for a comment... |
667 | // except when parsing the second parameter of the .symver directive. | |
668 | // Force the next symbol to allow @ in the identifier, which is | |
669 | // required for this directive and then reset it to its initial state. | |
670 | const bool AllowAtInIdentifier = getLexer().getAllowAtInIdentifier(); | |
671 | getLexer().setAllowAtInIdentifier(true); | |
223e47cc | 672 | Lex(); |
1a4d82fc | 673 | getLexer().setAllowAtInIdentifier(AllowAtInIdentifier); |
223e47cc LB |
674 | |
675 | StringRef AliasName; | |
970d7e83 | 676 | if (getParser().parseIdentifier(AliasName)) |
223e47cc LB |
677 | return TokError("expected identifier in directive"); |
678 | ||
679 | if (AliasName.find('@') == StringRef::npos) | |
680 | return TokError("expected a '@' in the name"); | |
681 | ||
682 | MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); | |
683 | MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); | |
684 | const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext()); | |
685 | ||
686 | getStreamer().EmitAssignment(Alias, Value); | |
687 | return false; | |
688 | } | |
689 | ||
690 | /// ParseDirectiveVersion | |
691 | /// ::= .version string | |
692 | bool ELFAsmParser::ParseDirectiveVersion(StringRef, SMLoc) { | |
693 | if (getLexer().isNot(AsmToken::String)) | |
694 | return TokError("unexpected token in '.version' directive"); | |
695 | ||
696 | StringRef Data = getTok().getIdentifier(); | |
697 | ||
698 | Lex(); | |
699 | ||
700 | const MCSection *Note = | |
701 | getContext().getELFSection(".note", ELF::SHT_NOTE, 0, | |
702 | SectionKind::getReadOnly()); | |
703 | ||
704 | getStreamer().PushSection(); | |
705 | getStreamer().SwitchSection(Note); | |
706 | getStreamer().EmitIntValue(Data.size()+1, 4); // namesz. | |
707 | getStreamer().EmitIntValue(0, 4); // descsz = 0 (no description). | |
708 | getStreamer().EmitIntValue(1, 4); // type = NT_VERSION. | |
970d7e83 | 709 | getStreamer().EmitBytes(Data); // name. |
223e47cc LB |
710 | getStreamer().EmitIntValue(0, 1); // terminate the string. |
711 | getStreamer().EmitValueToAlignment(4); // ensure 4 byte alignment. | |
712 | getStreamer().PopSection(); | |
713 | return false; | |
714 | } | |
715 | ||
716 | /// ParseDirectiveWeakref | |
717 | /// ::= .weakref foo, bar | |
718 | bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { | |
719 | // FIXME: Share code with the other alias building directives. | |
720 | ||
721 | StringRef AliasName; | |
970d7e83 | 722 | if (getParser().parseIdentifier(AliasName)) |
223e47cc LB |
723 | return TokError("expected identifier in directive"); |
724 | ||
725 | if (getLexer().isNot(AsmToken::Comma)) | |
726 | return TokError("expected a comma"); | |
727 | ||
728 | Lex(); | |
729 | ||
730 | StringRef Name; | |
970d7e83 | 731 | if (getParser().parseIdentifier(Name)) |
223e47cc LB |
732 | return TokError("expected identifier in directive"); |
733 | ||
734 | MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); | |
735 | ||
736 | MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); | |
737 | ||
738 | getStreamer().EmitWeakReference(Alias, Sym); | |
739 | return false; | |
740 | } | |
741 | ||
1a4d82fc JJ |
742 | bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) { |
743 | const MCExpr *Subsection = nullptr; | |
744 | if (getLexer().isNot(AsmToken::EndOfStatement)) { | |
745 | if (getParser().parseExpression(Subsection)) | |
746 | return true; | |
747 | } | |
748 | ||
749 | if (getLexer().isNot(AsmToken::EndOfStatement)) | |
750 | return TokError("unexpected token in directive"); | |
751 | ||
752 | getStreamer().SubSection(Subsection); | |
753 | return false; | |
754 | } | |
755 | ||
223e47cc LB |
756 | namespace llvm { |
757 | ||
758 | MCAsmParserExtension *createELFAsmParser() { | |
759 | return new ELFAsmParser; | |
760 | } | |
761 | ||
762 | } |