1 //===- ELFAsmParser.cpp - ELF Assembly Parser -----------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
23 class ELFAsmParser
: public MCAsmParserExtension
{
24 template<bool (ELFAsmParser::*Handler
)(StringRef
, SMLoc
)>
25 void AddDirectiveHandler(StringRef Directive
) {
26 getParser().AddDirectiveHandler(this, Directive
,
27 HandleDirective
<ELFAsmParser
, Handler
>);
30 bool ParseSectionSwitch(StringRef Section
, unsigned Type
,
31 unsigned Flags
, SectionKind Kind
);
36 virtual void Initialize(MCAsmParser
&Parser
) {
37 // Call the base implementation.
38 this->MCAsmParserExtension::Initialize(Parser
);
40 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveData
>(".data");
41 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveText
>(".text");
42 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveBSS
>(".bss");
43 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveRoData
>(".rodata");
44 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveTData
>(".tdata");
45 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveTBSS
>(".tbss");
46 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveDataRel
>(".data.rel");
47 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveDataRelRo
>(".data.rel.ro");
48 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal
>(".data.rel.ro.local");
49 AddDirectiveHandler
<&ELFAsmParser::ParseSectionDirectiveEhFrame
>(".eh_frame");
50 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveSection
>(".section");
51 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveSize
>(".size");
52 AddDirectiveHandler
<&ELFAsmParser::ParseDirectivePrevious
>(".previous");
53 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveType
>(".type");
54 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveIdent
>(".ident");
55 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveSymver
>(".symver");
56 AddDirectiveHandler
<&ELFAsmParser::ParseDirectiveWeakref
>(".weakref");
59 // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
60 // the best way for us to get access to it?
61 bool ParseSectionDirectiveData(StringRef
, SMLoc
) {
62 return ParseSectionSwitch(".data", MCSectionELF::SHT_PROGBITS
,
63 MCSectionELF::SHF_WRITE
|MCSectionELF::SHF_ALLOC
,
64 SectionKind::getDataRel());
66 bool ParseSectionDirectiveText(StringRef
, SMLoc
) {
67 return ParseSectionSwitch(".text", MCSectionELF::SHT_PROGBITS
,
68 MCSectionELF::SHF_EXECINSTR
|
69 MCSectionELF::SHF_ALLOC
, SectionKind::getText());
71 bool ParseSectionDirectiveBSS(StringRef
, SMLoc
) {
72 return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS
,
73 MCSectionELF::SHF_WRITE
|
74 MCSectionELF::SHF_ALLOC
, SectionKind::getBSS());
76 bool ParseSectionDirectiveRoData(StringRef
, SMLoc
) {
77 return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS
,
78 MCSectionELF::SHF_ALLOC
,
79 SectionKind::getReadOnly());
81 bool ParseSectionDirectiveTData(StringRef
, SMLoc
) {
82 return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS
,
83 MCSectionELF::SHF_ALLOC
|
84 MCSectionELF::SHF_TLS
| MCSectionELF::SHF_WRITE
,
85 SectionKind::getThreadData());
87 bool ParseSectionDirectiveTBSS(StringRef
, SMLoc
) {
88 return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS
,
89 MCSectionELF::SHF_ALLOC
|
90 MCSectionELF::SHF_TLS
| MCSectionELF::SHF_WRITE
,
91 SectionKind::getThreadBSS());
93 bool ParseSectionDirectiveDataRel(StringRef
, SMLoc
) {
94 return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS
,
95 MCSectionELF::SHF_ALLOC
|
96 MCSectionELF::SHF_WRITE
,
97 SectionKind::getDataRel());
99 bool ParseSectionDirectiveDataRelRo(StringRef
, SMLoc
) {
100 return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS
,
101 MCSectionELF::SHF_ALLOC
|
102 MCSectionELF::SHF_WRITE
,
103 SectionKind::getReadOnlyWithRel());
105 bool ParseSectionDirectiveDataRelRoLocal(StringRef
, SMLoc
) {
106 return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS
,
107 MCSectionELF::SHF_ALLOC
|
108 MCSectionELF::SHF_WRITE
,
109 SectionKind::getReadOnlyWithRelLocal());
111 bool ParseSectionDirectiveEhFrame(StringRef
, SMLoc
) {
112 return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS
,
113 MCSectionELF::SHF_ALLOC
|
114 MCSectionELF::SHF_WRITE
,
115 SectionKind::getDataRel());
117 bool ParseDirectiveSection(StringRef
, SMLoc
);
118 bool ParseDirectiveSize(StringRef
, SMLoc
);
119 bool ParseDirectivePrevious(StringRef
, SMLoc
);
120 bool ParseDirectiveType(StringRef
, SMLoc
);
121 bool ParseDirectiveIdent(StringRef
, SMLoc
);
122 bool ParseDirectiveSymver(StringRef
, SMLoc
);
123 bool ParseDirectiveWeakref(StringRef
, SMLoc
);
126 bool ParseSectionName(StringRef
&SectionName
);
131 bool ELFAsmParser::ParseSectionSwitch(StringRef Section
, unsigned Type
,
132 unsigned Flags
, SectionKind Kind
) {
133 if (getLexer().isNot(AsmToken::EndOfStatement
))
134 return TokError("unexpected token in section switching directive");
137 getStreamer().SwitchSection(getContext().getELFSection(
138 Section
, Type
, Flags
, Kind
));
143 bool ELFAsmParser::ParseDirectiveSize(StringRef
, SMLoc
) {
145 if (getParser().ParseIdentifier(Name
))
146 return TokError("expected identifier in directive");
147 MCSymbol
*Sym
= getContext().GetOrCreateSymbol(Name
);;
149 if (getLexer().isNot(AsmToken::Comma
))
150 return TokError("unexpected token in directive");
154 if (getParser().ParseExpression(Expr
))
157 if (getLexer().isNot(AsmToken::EndOfStatement
))
158 return TokError("unexpected token in directive");
160 getStreamer().EmitELFSize(Sym
, Expr
);
164 bool ELFAsmParser::ParseSectionName(StringRef
&SectionName
) {
165 // A section name can contain -, so we cannot just use
167 SMLoc FirstLoc
= getLexer().getLoc();
174 SMLoc PrevLoc
= getLexer().getLoc();
175 if (getLexer().is(AsmToken::Minus
)) {
177 Lex(); // Consume the "-".
178 } else if (!getParser().ParseIdentifier(Tmp
))
179 CurSize
= Tmp
.size();
184 SectionName
= StringRef(FirstLoc
.getPointer(), Size
);
186 // Make sure the following token is adjacent.
187 if (PrevLoc
.getPointer() + CurSize
!= getTok().getLoc().getPointer())
196 // FIXME: This is a work in progress.
197 bool ELFAsmParser::ParseDirectiveSection(StringRef
, SMLoc
) {
198 StringRef SectionName
;
200 if (ParseSectionName(SectionName
))
201 return TokError("expected identifier in directive");
206 if (getLexer().is(AsmToken::Comma
)) {
209 if (getLexer().isNot(AsmToken::String
))
210 return TokError("expected string in directive");
212 FlagsStr
= getTok().getStringContents();
215 AsmToken::TokenKind TypeStartToken
;
216 if (getContext().getAsmInfo().getCommentString()[0] == '@')
217 TypeStartToken
= AsmToken::Percent
;
219 TypeStartToken
= AsmToken::At
;
221 bool Mergeable
= FlagsStr
.find('M') != StringRef::npos
;
222 bool Group
= FlagsStr
.find('G') != StringRef::npos
;
224 if (getLexer().isNot(AsmToken::Comma
)) {
226 return TokError("Mergeable section must specify the type");
228 return TokError("Group section must specify the type");
231 if (getLexer().isNot(TypeStartToken
))
232 return TokError("expected the type");
235 if (getParser().ParseIdentifier(TypeName
))
236 return TokError("expected identifier in directive");
239 if (getLexer().isNot(AsmToken::Comma
))
240 return TokError("expected the entry size");
242 if (getParser().ParseAbsoluteExpression(Size
))
245 return TokError("entry size must be positive");
249 if (getLexer().isNot(AsmToken::Comma
))
250 return TokError("expected group name");
253 if (getParser().ParseIdentifier(GroupName
))
255 if (getLexer().is(AsmToken::Comma
)) {
258 if (getParser().ParseIdentifier(Linkage
))
260 if (Linkage
!= "comdat" && Linkage
!= ".gnu.linkonce")
261 return TokError("Linkage must be 'comdat' or '.gnu.linkonce'");
267 if (getLexer().isNot(AsmToken::EndOfStatement
))
268 return TokError("unexpected token in directive");
271 unsigned Type
= MCSectionELF::SHT_NULL
;
273 // Set the defaults first.
274 if (SectionName
== ".fini" || SectionName
== ".init") {
275 Type
= MCSectionELF::SHT_PROGBITS
;
276 Flags
|= MCSectionELF::SHF_ALLOC
;
277 Flags
|= MCSectionELF::SHF_EXECINSTR
;
280 for (unsigned i
= 0; i
< FlagsStr
.size(); i
++) {
281 switch (FlagsStr
[i
]) {
283 Flags
|= MCSectionELF::SHF_ALLOC
;
286 Flags
|= MCSectionELF::SHF_EXECINSTR
;
289 Flags
|= MCSectionELF::SHF_WRITE
;
292 Flags
|= MCSectionELF::SHF_MERGE
;
295 Flags
|= MCSectionELF::SHF_STRINGS
;
298 Flags
|= MCSectionELF::SHF_TLS
;
301 Flags
|= MCSectionELF::XCORE_SHF_CP_SECTION
;
304 Flags
|= MCSectionELF::XCORE_SHF_DP_SECTION
;
309 return TokError("unknown flag");
313 if (!TypeName
.empty()) {
314 if (TypeName
== "init_array")
315 Type
= MCSectionELF::SHT_INIT_ARRAY
;
316 else if (TypeName
== "fini_array")
317 Type
= MCSectionELF::SHT_FINI_ARRAY
;
318 else if (TypeName
== "preinit_array")
319 Type
= MCSectionELF::SHT_PREINIT_ARRAY
;
320 else if (TypeName
== "nobits")
321 Type
= MCSectionELF::SHT_NOBITS
;
322 else if (TypeName
== "progbits")
323 Type
= MCSectionELF::SHT_PROGBITS
;
325 return TokError("unknown section type");
328 SectionKind Kind
= (Flags
& MCSectionELF::SHF_EXECINSTR
)
329 ? SectionKind::getText()
330 : SectionKind::getDataRel();
331 getStreamer().SwitchSection(getContext().getELFSection(SectionName
, Type
,
337 bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName
, SMLoc
) {
338 const MCSection
*PreviousSection
= getStreamer().getPreviousSection();
339 if (PreviousSection
!= NULL
)
340 getStreamer().SwitchSection(PreviousSection
);
345 /// ParseDirectiveELFType
346 /// ::= .type identifier , @attribute
347 bool ELFAsmParser::ParseDirectiveType(StringRef
, SMLoc
) {
349 if (getParser().ParseIdentifier(Name
))
350 return TokError("expected identifier in directive");
352 // Handle the identifier as the key symbol.
353 MCSymbol
*Sym
= getContext().GetOrCreateSymbol(Name
);
355 if (getLexer().isNot(AsmToken::Comma
))
356 return TokError("unexpected token in '.type' directive");
359 if (getLexer().isNot(AsmToken::At
))
360 return TokError("expected '@' before type");
366 TypeLoc
= getLexer().getLoc();
367 if (getParser().ParseIdentifier(Type
))
368 return TokError("expected symbol type in directive");
370 MCSymbolAttr Attr
= StringSwitch
<MCSymbolAttr
>(Type
)
371 .Case("function", MCSA_ELF_TypeFunction
)
372 .Case("object", MCSA_ELF_TypeObject
)
373 .Case("tls_object", MCSA_ELF_TypeTLS
)
374 .Case("common", MCSA_ELF_TypeCommon
)
375 .Case("notype", MCSA_ELF_TypeNoType
)
376 .Default(MCSA_Invalid
);
378 if (Attr
== MCSA_Invalid
)
379 return Error(TypeLoc
, "unsupported attribute in '.type' directive");
381 if (getLexer().isNot(AsmToken::EndOfStatement
))
382 return TokError("unexpected token in '.type' directive");
386 getStreamer().EmitSymbolAttribute(Sym
, Attr
);
391 /// ParseDirectiveIdent
392 /// ::= .ident string
393 bool ELFAsmParser::ParseDirectiveIdent(StringRef
, SMLoc
) {
394 if (getLexer().isNot(AsmToken::String
))
395 return TokError("unexpected token in '.ident' directive");
397 StringRef Data
= getTok().getIdentifier();
401 const MCSection
*OldSection
= getStreamer().getCurrentSection();
402 const MCSection
*Comment
=
403 getContext().getELFSection(".comment", MCSectionELF::SHT_PROGBITS
,
404 MCSectionELF::SHF_MERGE
|
405 MCSectionELF::SHF_STRINGS
,
406 SectionKind::getReadOnly(),
409 static bool First
= true;
411 getStreamer().SwitchSection(Comment
);
413 getStreamer().EmitIntValue(0, 1);
415 getStreamer().EmitBytes(Data
, 0);
416 getStreamer().EmitIntValue(0, 1);
417 getStreamer().SwitchSection(OldSection
);
421 /// ParseDirectiveSymver
422 /// ::= .symver foo, bar2@zed
423 bool ELFAsmParser::ParseDirectiveSymver(StringRef
, SMLoc
) {
425 if (getParser().ParseIdentifier(Name
))
426 return TokError("expected identifier in directive");
428 if (getLexer().isNot(AsmToken::Comma
))
429 return TokError("expected a comma");
434 if (getParser().ParseIdentifier(AliasName
))
435 return TokError("expected identifier in directive");
437 if (AliasName
.find('@') == StringRef::npos
)
438 return TokError("expected a '@' in the name");
440 MCSymbol
*Alias
= getContext().GetOrCreateSymbol(AliasName
);
441 MCSymbol
*Sym
= getContext().GetOrCreateSymbol(Name
);
442 const MCExpr
*Value
= MCSymbolRefExpr::Create(Sym
, getContext());
444 getStreamer().EmitAssignment(Alias
, Value
);
448 /// ParseDirectiveWeakref
449 /// ::= .weakref foo, bar
450 bool ELFAsmParser::ParseDirectiveWeakref(StringRef
, SMLoc
) {
451 // FIXME: Share code with the other alias building directives.
454 if (getParser().ParseIdentifier(AliasName
))
455 return TokError("expected identifier in directive");
457 if (getLexer().isNot(AsmToken::Comma
))
458 return TokError("expected a comma");
463 if (getParser().ParseIdentifier(Name
))
464 return TokError("expected identifier in directive");
466 MCSymbol
*Alias
= getContext().GetOrCreateSymbol(AliasName
);
468 MCSymbol
*Sym
= getContext().GetOrCreateSymbol(Name
);
470 getStreamer().EmitWeakReference(Alias
, Sym
);
476 MCAsmParserExtension
*createELFAsmParser() {
477 return new ELFAsmParser
;