X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMCELFStreamer.cpp;h=1f4f1461a571479c938f0e3f18cbbe69398ad91b;hb=1f4f9e3d35a2264d86f97dfb6d1e4ccb434f449b;hp=65a0a7d7e651cdce358ae0c38e0fc72804992d78;hpb=3223f19ff0920ffee686faba3bf74babf580e8a5;p=oota-llvm.git diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 65a0a7d7e65..1f4f1461a57 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/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" @@ -34,9 +35,39 @@ using namespace llvm; namespace { +static void SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} + +static unsigned GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +static void SetType(MCSymbolData &SD, unsigned Type) { + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_FILE || Type == ELF::STT_COMMON || + Type == ELF::STT_TLS); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); + SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); +} + +static void SetVisibility(MCSymbolData &SD, unsigned Visibility) { + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STV_Shift); + SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); +} + class MCELFStreamer : public MCObjectStreamer { - void EmitInstToFragment(const MCInst &Inst); - void EmitInstToData(const MCInst &Inst); public: MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) @@ -50,7 +81,10 @@ public: virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void SwitchSection(const MCSection *Section); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -107,10 +141,12 @@ public: DEBUG(dbgs() << "FIXME: MCELFStreamer:EmitDwarfFileDirective not implemented\n"); } - virtual void EmitInstruction(const MCInst &Inst); virtual void Finish(); private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + struct LocalCommon { MCSymbolData *SD; uint64_t Size; @@ -163,6 +199,11 @@ void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + const MCSectionELF &Section = + static_cast(Symbol->getSection()); + if (Section.getFlags() & MCSectionELF::SHF_TLS) + SetType(SD, ELF::STT_TLS); + // FIXME: This is wasteful, we don't necessarily need to create a data // fragment. Instead, we should mark the symbol as pointing into the data // fragment if it exists, otherwise we should just queue the label and set its @@ -176,7 +217,9 @@ void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { - case MCAF_SyntaxUnified: return; // no-op here? + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; @@ -185,6 +228,10 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { assert(0 && "invalid assembler flag!"); } +void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { + // FIXME: Anything needed here to flag the function as thumb? +} + void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into // MCObjectStreamer. @@ -193,36 +240,71 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } -static void SetBinding(MCSymbolData &SD, unsigned Binding) { - assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || - Binding == ELF::STB_WEAK); - uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); - SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); -} +// 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. -static unsigned GetBinding(const MCSymbolData &SD) { - uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; - assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || - Binding == ELF::STB_WEAK); - return Binding; -} +namespace { +class WeakRefExpr : public MCTargetExpr { +private: + const MCSymbolRefExpr *Alias; -static void SetType(MCSymbolData &SD, unsigned Type) { - assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || - Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || - Type == ELF::STT_FILE || Type == ELF::STT_COMMON || - Type == ELF::STT_TLS); + explicit WeakRefExpr(const MCSymbolRefExpr *Alias_) + : MCTargetExpr(), Alias(Alias_) {} - uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); - SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); +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); + } +}; +} // end anonymous namespace + +void MCELFStreamer::SwitchSection(const MCSection *Section) { + const MCSymbol *Grp = static_cast(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::SwitchSection(Section); } -static void SetVisibility(MCSymbolData &SD, unsigned Visibility) { - assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || - Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); - uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STV_Shift); - SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); + // 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); } void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, @@ -263,6 +345,10 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, assert(0 && "Invalid symbol attribute for ELF!"); break; + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. + break; + case MCSA_Global: SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); @@ -450,36 +536,16 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { DF->getContents().append(Code.begin(), Code.end()); } -void MCELFStreamer::EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = 0; i != Inst.getNumOperands(); ++i) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - - getCurrentSectionData()->setHasInstructions(true); - - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } - - // Otherwise, if we are relaxing everything, relax the instruction as much as - // possible and emit it as data. - if (getAssembler().getRelaxAll()) { - MCInst Relaxed; - getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); - while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) - getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); - EmitInstToData(Relaxed); - return; +void MCELFStreamer::Finish() { + // FIXME: duplicated code with the MachO streamer. + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles()) { + const MCSection *DwarfLineSection = + getContext().getELFSection(".debug_line", 0, 0, + SectionKind::getDataRelLocal()); + MCDwarfFileTable::Emit(this, DwarfLineSection); } - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} - -void MCELFStreamer::Finish() { for (std::vector::const_iterator i = LocalCommons.begin(), e = LocalCommons.end(); i != e; ++i) {