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

@ -21,9 +21,10 @@
namespace llvm {
enum {
ELF_STT_Shift = 0, // Shift value for STT_* flags.
ELF_STB_Shift = 4, // Shift value for STB_* flags.
ELF_STV_Shift = 8 // Shift value ofr STV_* flags.
ELF_STT_Shift = 0, // Shift value for STT_* flags.
ELF_STB_Shift = 4, // Shift value for STB_* flags.
ELF_STV_Shift = 8, // Shift value for STV_* flags.
ELF_Other_Shift = 10 // Shift value for other flags.
};
enum SymbolFlags {
@ -46,7 +47,9 @@ namespace llvm {
ELF_STV_Default = (ELF::STV_DEFAULT << ELF_STV_Shift),
ELF_STV_Internal = (ELF::STV_INTERNAL << ELF_STV_Shift),
ELF_STV_Hidden = (ELF::STV_HIDDEN << ELF_STV_Shift),
ELF_STV_Protected = (ELF::STV_PROTECTED << ELF_STV_Shift)
ELF_STV_Protected = (ELF::STV_PROTECTED << ELF_STV_Shift),
ELF_Other_Weakref = (1 << ELF_Other_Shift)
};
} // end namespace llvm

View File

@ -57,6 +57,7 @@ public:
/// @name MCStreamer Interface
/// @{
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
virtual void SwitchSection(const MCSection *Section);
virtual void Finish();

View File

@ -139,6 +139,15 @@ namespace llvm {
/// @param Value - The value for the symbol.
virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) = 0;
/// EmitWeakReference - Emit an weak reference from @p Alias to @p Symbol.
///
/// This corresponds to an assembler statement such as:
/// .weakref alias, symbol
///
/// @param Alias - The alias that is being created.
/// @param Symbol - The symbol being aliased.
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) = 0;
/// EmitSymbolAttribute - Add the given @p Attribute to @p Symbol.
virtual void EmitSymbolAttribute(MCSymbol *Symbol,
MCSymbolAttr Attribute) = 0;

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"

234
test/MC/ELF/weakref.s Normal file
View File

@ -0,0 +1,234 @@
// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump | FileCheck %s
// This is a long test that checks that the aliases created by weakref are
// never in the symbol table and that the only case it causes a symbol to
// be output as a weak undefined symbol is if that variable is not defined
// in this file and all the references to it are done via the alias.
.weakref foo1, bar1
.weakref foo2, bar2
.long bar2
.weakref foo3, bar3
.long foo3
.weakref foo4, bar4
.long foo4
.long bar4
.weakref foo5, bar5
.long bar5
.long foo5
bar6:
.weakref foo6, bar6
bar7:
.weakref foo7, bar7
.long bar7
bar8:
.weakref foo8, bar8
.long foo8
bar9:
.weakref foo9, bar9
.long foo9
.long bar9
bar10:
.global bar10
.weakref foo10, bar10
.long bar10
.long foo10
bar11:
.global bar11
.weakref foo11, bar11
bar12:
.global bar12
.weakref foo12, bar12
.long bar12
bar13:
.global bar13
.weakref foo13, bar13
.long foo13
bar14:
.global bar14
.weakref foo14, bar14
.long foo14
.long bar14
bar15:
.global bar15
.weakref foo15, bar15
.long bar15
.long foo15
// CHECK: # Symbol 0x00000000
// CHECK-NEXT: (('st_name', 0x00000000) # ''
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000000)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000001
// CHECK-NEXT: (('st_name', 0x00000015) # 'bar6'
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000018)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000002
// CHECK-NEXT: (('st_name', 0x0000001a) # 'bar7'
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000018)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000003
// CHECK-NEXT: (('st_name', 0x0000001f) # 'bar8'
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x0000001c)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000004
// CHECK-NEXT: (('st_name', 0x00000024) # 'bar9'
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000020)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000005
// CHECK-NEXT: (('st_name', 0x00000000) # ''
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000003)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000006
// CHECK-NEXT: (('st_name', 0x00000000) # ''
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000003)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000002)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000007
// CHECK-NEXT: (('st_name', 0x00000000) # ''
// CHECK-NEXT: ('st_bind', 0x00000000)
// CHECK-NEXT: ('st_type', 0x00000003)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000003)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000008
// CHECK-NEXT: (('st_name', 0x00000029) # 'bar10'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000028)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000009
// CHECK-NEXT: (('st_name', 0x0000002f) # 'bar11'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000030)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000a
// CHECK-NEXT: (('st_name', 0x00000035) # 'bar12'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000030)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000b
// CHECK-NEXT: (('st_name', 0x0000003b) # 'bar13'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000034)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000c
// CHECK-NEXT: (('st_name', 0x00000041) # 'bar14'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000038)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000d
// CHECK-NEXT: (('st_name', 0x00000047) # 'bar15'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000001)
// CHECK-NEXT: ('st_value', 0x00000040)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000e
// CHECK-NEXT: (('st_name', 0x00000001) # 'bar2'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000000)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x0000000f
// CHECK-NEXT: (('st_name', 0x00000006) # 'bar3'
// CHECK-NEXT: ('st_bind', 0x00000002)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000000)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000010
// CHECK-NEXT: (('st_name', 0x0000000b) # 'bar4'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000000)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: # Symbol 0x00000011
// CHECK-NEXT: (('st_name', 0x00000010) # 'bar5'
// CHECK-NEXT: ('st_bind', 0x00000001)
// CHECK-NEXT: ('st_type', 0x00000000)
// CHECK-NEXT: ('st_other', 0x00000000)
// CHECK-NEXT: ('st_shndx', 0x00000000)
// CHECK-NEXT: ('st_value', 0x00000000)
// CHECK-NEXT: ('st_size', 0x00000000)
// CHECK-NEXT: ),
// CHECK-NEXT: ])