diff options
Diffstat (limited to 'lib/MC/MCELFStreamer.cpp')
-rw-r--r-- | lib/MC/MCELFStreamer.cpp | 350 |
1 files changed, 234 insertions, 116 deletions
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 570c391..e49074d 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" @@ -23,19 +24,51 @@ #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" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" 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) @@ -46,9 +79,13 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); + virtual void ChangeSection(const MCSection *Section); 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 EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -76,9 +113,8 @@ public: SD.setSize(Value); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { - assert(0 && "ELF doesn't support this directive"); - } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) { assert(0 && "ELF doesn't support this directive"); @@ -88,49 +124,84 @@ public: assert(0 && "ELF doesn't support this directive"); } virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitGPRel32Value(const MCExpr *Value) { - assert(0 && "ELF doesn't support this directive"); - } virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); - virtual void EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - 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); + + void fixSymbolsInTLSFixups(const MCExpr *expr); + + struct LocalCommon { + MCSymbolData *SD; + uint64_t Size; + unsigned ByteAlignment; + }; + std::vector<LocalCommon> LocalCommons; + + SmallPtrSet<MCSymbol *, 16> BindingExplicitlySet; /// @} + void SetSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); + } + + void SetSectionData() { + SetSection(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + void SetSectionText() { + SetSection(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + void SetSectionBss() { + SetSection(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } }; } // end anonymous namespace. +void MCELFStreamer::InitSections() { + // This emulates the same behavior of GNU as. This makes it easier + // to compare the output as the major sections are in the same order. + SetSectionText(); + SetSectionData(); + SetSectionBss(); + SetSectionText(); +} + void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - // 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 - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); - Symbol->setSection(*CurSection); + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(Symbol->getSection()); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + if (Section.getFlags() & ELF::SHF_TLS) + SetType(SD, ELF::STT_TLS); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { + 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; @@ -139,6 +210,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. @@ -147,6 +222,21 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } +void MCELFStreamer::ChangeSection(const MCSection *Section) { + const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::ChangeSection(Section); +} + +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); + const MCExpr *Value = MCSymbolRefExpr::Create(Symbol, getContext()); + Alias->setVariableValue(Value); +} + void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { // Indirect symbols are handled differently, to match how 'as' handles @@ -176,6 +266,7 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_LazyReference: case MCSA_Reference: case MCSA_NoDeadStrip: + case MCSA_SymbolResolver: case MCSA_PrivateExtern: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: @@ -185,50 +276,59 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, assert(0 && "Invalid symbol attribute for ELF!"); break; + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. + break; + case MCSA_Global: - SD.setFlags(SD.getFlags() | ELF_STB_Global); + SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_WeakReference: case MCSA_Weak: - SD.setFlags(SD.getFlags() | ELF_STB_Weak); + SetBinding(SD, ELF::STB_WEAK); + SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_Local: - SD.setFlags(SD.getFlags() | ELF_STB_Local); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); break; case MCSA_ELF_TypeFunction: - SD.setFlags(SD.getFlags() | ELF_STT_Func); + SetType(SD, ELF::STT_FUNC); break; case MCSA_ELF_TypeObject: - SD.setFlags(SD.getFlags() | ELF_STT_Object); + SetType(SD, ELF::STT_OBJECT); break; case MCSA_ELF_TypeTLS: - SD.setFlags(SD.getFlags() | ELF_STT_Tls); + SetType(SD, ELF::STT_TLS); break; case MCSA_ELF_TypeCommon: - SD.setFlags(SD.getFlags() | ELF_STT_Common); + SetType(SD, ELF::STT_COMMON); break; case MCSA_ELF_TypeNoType: - SD.setFlags(SD.getFlags() | ELF_STT_Notype); + SetType(SD, ELF::STT_NOTYPE); break; case MCSA_Protected: - SD.setFlags(SD.getFlags() | ELF_STV_Protected); + SetVisibility(SD, ELF::STV_PROTECTED); break; case MCSA_Hidden: - SD.setFlags(SD.getFlags() | ELF_STV_Hidden); + SetVisibility(SD, ELF::STV_HIDDEN); break; case MCSA_Internal: - SD.setFlags(SD.getFlags() | ELF_STV_Internal); + SetVisibility(SD, ELF::STV_INTERNAL); break; } } @@ -237,24 +337,38 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - if ((SD.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local) { + if (!BindingExplicitlySet.count(Symbol)) { + SetBinding(SD, ELF::STB_GLOBAL); + SD.setExternal(true); + } + + SetType(SD, ELF::STT_OBJECT); + + if (GetBinding(SD) == ELF_STB_Local) { const MCSection *Section = getAssembler().getContext().getELFSection(".bss", - MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, + ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); - - MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section); - MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); - SD.setFragment(F); Symbol->setSection(*Section); - SD.setSize(MCConstantExpr::Create(Size, getContext())); + + struct LocalCommon L = {&SD, Size, ByteAlignment}; + LocalCommons.push_back(L); + } else { + SD.setCommon(Size, ByteAlignment); } - SD.setFlags(SD.getFlags() | ELF_STB_Global); - SD.setExternal(true); + SD.setSize(MCConstantExpr::Create(Size, getContext())); +} - SD.setCommon(Size, ByteAlignment); +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + // FIXME: Should this be caught and done earlier? + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + // FIXME: ByteAlignment is not needed here, but is required. + EmitCommonSymbol(Symbol, Size, 1); } void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { @@ -263,25 +377,6 @@ void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void MCELFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - MCDataFragment *DF = getOrCreateDataFragment(); - - // Avoid fixups when possible. - int64_t AbsValue; - if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { - // FIXME: Endianness assumption. - for (unsigned i = 0; i != Size; ++i) - DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); - } else { - DF->addFixup(MCFixup::Create(DF->getContents().size(), AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); - DF->getContents().resize(DF->getContents().size() + Size, 0); - } -} - void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { @@ -312,18 +407,11 @@ void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void MCELFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - // TODO: This is exactly the same as MCMachOStreamer. Consider merging into - // MCObjectStreamer. - new MCOrgFragment(*Offset, Value, getCurrentSectionData()); -} - // Add a symbol for the file name of this module. This is the second // entry in the module's symbol table (the first being the null symbol). void MCELFStreamer::EmitFileDirective(StringRef Filename) { MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename); - Symbol->setSection(*CurSection); + Symbol->setSection(*getCurrentSection()); Symbol->setAbsolute(); MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); @@ -331,21 +419,52 @@ void MCELFStreamer::EmitFileDirective(StringRef Filename) { SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); } -void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); +void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { + switch (expr->getKind()) { + case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Constant: + break; - // Add the fixups and data. - // - // FIXME: Revisit this design decision when relaxation is done, we may be - // able to get away with not storing any extra data in the MCInst. - SmallVector<MCFixup, 4> Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); - VecOS.flush(); + case MCExpr::Binary: { + const MCBinaryExpr *be = cast<MCBinaryExpr>(expr); + fixSymbolsInTLSFixups(be->getLHS()); + fixSymbolsInTLSFixups(be->getRHS()); + break; + } + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr); + switch (symRef.getKind()) { + default: + return; + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + case MCSymbolRefExpr::VK_ARM_TLSGD: + break; + } + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(symRef.getSymbol()); + SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr()); + break; + } +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + this->MCObjectStreamer::EmitInstToFragment(Inst); + MCInstFragment &F = *cast<MCInstFragment>(getCurrentFragment()); - IF->getCode() = Code; - IF->getFixups() = Fixups; + for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) + fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); } void MCELFStreamer::EmitInstToData(const MCInst &Inst) { @@ -357,6 +476,9 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + fixSymbolsInTLSFixups(Fixups[i].getValue()); + // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); @@ -365,44 +487,40 @@ 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()); +void MCELFStreamer::Finish() { + if (getNumFrameInfos()) + MCDwarfFrameEmitter::Emit(*this); - getCurrentSectionData()->setHasInstructions(true); + for (std::vector<LocalCommon>::const_iterator i = LocalCommons.begin(), + e = LocalCommons.end(); + i != e; ++i) { + MCSymbolData *SD = i->SD; + uint64_t Size = i->Size; + unsigned ByteAlignment = i->ByteAlignment; + const MCSymbol &Symbol = SD->getSymbol(); + const MCSection &Section = Symbol.getSection(); - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } + MCSectionData &SectData = getAssembler().getOrCreateSectionData(Section); + new MCAlignFragment(ByteAlignment, 0, 1, ByteAlignment, &SectData); - // 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; - } + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD->setFragment(F); - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} + // Update the maximum alignment of the section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); + } -void MCELFStreamer::Finish() { - getAssembler().Finish(); + this->MCObjectStreamer::Finish(); } MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll) { + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll, bool NoExecStack) { MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); if (RelaxAll) S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); return S; } |