Implement .weakref.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@117911 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola
2010-11-01 14:28:48 +00:00
parent 69661191ce
commit 484291c273
12 changed files with 372 additions and 6 deletions

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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){}

View File

@@ -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!");

View File

@@ -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() {

View File

@@ -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"