diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2010-11-01 14:28:48 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2010-11-01 14:28:48 +0000 |
commit | 1614597873fa80a8d56d42ab20230ca260daa448 (patch) | |
tree | 95a43b67d1013f8b8b89e808d6165937d4da688c /llvm/lib | |
parent | 1cbdd951e8e5be4df936a62f4a416d70f8a8ba40 (diff) | |
download | bcm5719-llvm-1614597873fa80a8d56d42ab20230ca260daa448.tar.gz bcm5719-llvm-1614597873fa80a8d56d42ab20230ca260daa448.zip |
Implement .weakref.
llvm-svn: 117911
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/MC/ELFObjectWriter.cpp | 17 | ||||
-rw-r--r-- | llvm/lib/MC/MCAsmStreamer.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/MC/MCELFStreamer.cpp | 60 | ||||
-rw-r--r-- | llvm/lib/MC/MCLoggingStreamer.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/MC/MCNullStreamer.cpp | 1 | ||||
-rw-r--r-- | llvm/lib/MC/MCObjectStreamer.cpp | 5 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/ELFAsmParser.cpp | 28 | ||||
-rw-r--r-- | llvm/lib/MC/MCStreamer.cpp | 1 |
8 files changed, 121 insertions, 2 deletions
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp index 850983fa1a0..a0e326db284 100644 --- a/llvm/lib/MC/ELFObjectWriter.cpp +++ b/llvm/lib/MC/ELFObjectWriter.cpp @@ -143,6 +143,7 @@ namespace { }; SmallPtrSet<const MCSymbol *, 16> UsedInReloc; + SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc; DenseMap<const MCSymbol *, const MCSymbol *> Renames; llvm::DenseMap<const MCSectionData*, @@ -691,7 +692,7 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, Symbol = &AliasedSymbol(Target.getSymA()->getSymbol()); Renamed = Renames.lookup(Symbol); if (!Renamed) - Renamed = Symbol; + Renamed = &Target.getSymA()->getSymbol(); MCSymbolData &SD = Asm.getSymbolData(*Symbol); MCFragment *F = SD.getFragment(); @@ -727,6 +728,10 @@ void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); } else { UsedInReloc.insert(Renamed); + MCSymbolData &RenamedSD = Asm.getSymbolData(*Renamed); + if (RenamedSD.getFlags() & ELF_Other_Weakref) { + WeakrefUsedInReloc.insert(Symbol); + } Index = -1; } Addend = Value; @@ -901,6 +906,9 @@ ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, bool Used, bool Renamed) { + if (Data.getFlags() & ELF_Other_Weakref) + return false; + if (Used) return true; @@ -963,7 +971,9 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); - if (!isInSymtab(Asm, *it, UsedInReloc.count(&Symbol), + bool Used = UsedInReloc.count(&Symbol); + bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); + if (!isInSymtab(Asm, *it, Used || WeakrefUsed, Renames.count(&Symbol))) continue; @@ -972,6 +982,9 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { bool Local = isLocal(*it); const MCSymbol &RefSymbol = AliasedSymbol(Symbol); + if (RefSymbol.isUndefined() && !Used && WeakrefUsed) + SetBinding(*it, ELF::STB_WEAK); + if (it->isCommon()) { assert(!Local); MSD.SectionIndex = ELF::SHN_COMMON; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 6c240cf4148..ca8dc965f29 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -113,6 +113,7 @@ public: virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); @@ -258,6 +259,11 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(Value); } +void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + OS << ".weakref " << *Alias << ", " << *Symbol; + EmitEOL(); +} + void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp index 65a0a7d7e65..e794e57e93a 100644 --- a/llvm/lib/MC/MCELFStreamer.cpp +++ b/llvm/lib/MC/MCELFStreamer.cpp @@ -24,6 +24,7 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" @@ -51,6 +52,7 @@ public: virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -193,6 +195,64 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } +// This is a hack. To be able to implement weakrefs the writer has to be able +// to distinguish +// .weakref foo, bar +// .long foo +// from +// .weakref foo, bar +// .long bar +// since the first case should produce a weak undefined reference and the second +// one a strong one. +// If we created foo as a regular alias pointing to bar (foo = bar), then +// MCExpr::EvaluateAsRelocatable would recurse on foo and the writer would +// never see it used in a relocation. +// What we do is create a MCTargetExpr that when evaluated produces a symbol +// ref to a temporary symbol. This temporary symbol in turn is a variable +// that equals the original symbol (tmp = bar). With this hack the writer +// gets a relocation with tmp and can correctly implement weak references. + +class WeakRefExpr : public MCTargetExpr { +private: + const MCSymbolRefExpr *Alias; + + explicit WeakRefExpr(const MCSymbolRefExpr *Alias_) + : MCTargetExpr(), Alias(Alias_) {} + +public: + virtual void PrintImpl(raw_ostream &OS) const { + llvm_unreachable("Unimplemented"); + } + + virtual bool EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { + Res = MCValue::get(Alias, 0, 0); + return true; + } + + static const WeakRefExpr *Create(const MCSymbol *Alias, MCContext &Ctx) { + const MCSymbolRefExpr *A = MCSymbolRefExpr::Create(Alias, Ctx); + return new (Ctx) WeakRefExpr(A); + } +}; + +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); + + // Create the alias that actually points to Symbol + const MCSymbolRefExpr *SymRef = MCSymbolRefExpr::Create(Symbol, getContext()); + MCSymbol *RealAlias = getContext().CreateTempSymbol(); + RealAlias->setVariableValue(SymRef); + + MCSymbolData &RealAliasSD = getAssembler().getOrCreateSymbolData(*RealAlias); + RealAliasSD.setFlags(RealAliasSD.getFlags() | ELF_Other_Weakref); + + const MCExpr *Value = WeakRefExpr::Create(RealAlias, getContext()); + Alias->setVariableValue(Value); +} + static void SetBinding(MCSymbolData &SD, unsigned Binding) { assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK); diff --git a/llvm/lib/MC/MCLoggingStreamer.cpp b/llvm/lib/MC/MCLoggingStreamer.cpp index 761574545f7..a907c11f118 100644 --- a/llvm/lib/MC/MCLoggingStreamer.cpp +++ b/llvm/lib/MC/MCLoggingStreamer.cpp @@ -74,6 +74,11 @@ public: return Child->EmitAssignment(Symbol, Value); } + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + LogCall("EmitWeakReference"); + return Child->EmitWeakReference(Alias, Symbol); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { LogCall("EmitSymbolAttribute"); return Child->EmitSymbolAttribute(Symbol, Attribute); diff --git a/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp index b2db410c111..5f29b46d370 100644 --- a/llvm/lib/MC/MCNullStreamer.cpp +++ b/llvm/lib/MC/MCNullStreamer.cpp @@ -42,6 +42,7 @@ namespace { virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp index 8a481e8bb30..3883f121522 100644 --- a/llvm/lib/MC/MCObjectStreamer.cpp +++ b/llvm/lib/MC/MCObjectStreamer.cpp @@ -74,6 +74,11 @@ const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { return Value; } +void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias, + const MCSymbol *Symbol) { + report_fatal_error("This file format doesn't support weak aliases."); +} + void MCObjectStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp index 62cf6c6e7a0..9883018dd15 100644 --- a/llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -53,6 +53,7 @@ public: AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); } // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is @@ -119,6 +120,7 @@ public: bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveIdent(StringRef, SMLoc); bool ParseDirectiveSymver(StringRef, SMLoc); + bool ParseDirectiveWeakref(StringRef, SMLoc); private: bool ParseSectionName(StringRef &SectionName); @@ -443,6 +445,32 @@ bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { return false; } +/// ParseDirectiveWeakref +/// ::= .weakref foo, bar +bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { + // FIXME: Share code with the other alias building directives. + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + getStreamer().EmitWeakReference(Alias, Sym); + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() { diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index 54071eba463..351d9fce4c3 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" |