X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMCELFStreamer.cpp;h=180a58cf6d144df6c268af98eed5730c12013766;hb=6e08a410aa0a375450dfbdd3c1114aafc5fb1fb9;hp=7252c90c17633e880abe68d2502cff1b37a78fe6;hpb=f89671d994ba27e2816a7e49eb8bbc1b43d2a147;p=oota-llvm.git diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 7252c90c176..180a58cf6d1 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -1,4 +1,4 @@ -//===- lib/MC/MCELFStreamer.cpp - ELF Object Output ------------===// +//===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===// // // The LLVM Compiler Infrastructure // @@ -11,12 +11,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCStreamer.h" - +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELF.h" #include "llvm/MC/MCELFSymbolFlags.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -29,125 +31,45 @@ #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetAsmBackend.h" using namespace llvm; -namespace { - -class MCELFStreamer : public MCObjectStreamer { -public: - MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *Emitter) - : MCObjectStreamer(Context, TAB, OS, Emitter, false) {} - - ~MCELFStreamer() {} - - /// @name MCStreamer Interface - /// @{ - - virtual void InitSections(); - 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"); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolStorageClass(int StorageClass) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitCOFFSymbolType(int Type) { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EndCOFFSymbolDef() { - assert(0 && "ELF doesn't support this directive"); - } - - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - SD.setSize(Value); - } - - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { - assert(0 && "ELF doesn't support this directive"); - } - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, - unsigned Size = 0, unsigned ByteAlignment = 0) { - assert(0 && "ELF doesn't support this directive"); - } - virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment = 0) { - 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 Finish(); +inline void MCELFStreamer::SetSection(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); +} -private: - virtual void EmitInstToFragment(const MCInst &Inst); - virtual void EmitInstToData(const MCInst &Inst); +inline void MCELFStreamer::SetSectionData() { + SetSection(".data", + ELF::SHT_PROGBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); +} - struct LocalCommon { - MCSymbolData *SD; - uint64_t Size; - unsigned ByteAlignment; - }; - std::vector LocalCommons; +inline void MCELFStreamer::SetSectionText() { + SetSection(".text", + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText()); + EmitCodeAlignment(4, 0); +} - SmallPtrSet BindingExplicitlySet; - /// @} - void SetSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind) { - SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); - } +inline void MCELFStreamer::SetSectionBss() { + SetSection(".bss", + ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); +} - void SetSectionData() { - SetSection(".data", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, - SectionKind::getDataRel()); - EmitCodeAlignment(4, 0); - } - void SetSectionText() { - SetSection(".text", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_EXECINSTR | - MCSectionELF::SHF_ALLOC, SectionKind::getText()); - EmitCodeAlignment(4, 0); - } - void SetSectionBss() { - SetSection(".bss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, SectionKind::getBSS()); - EmitCodeAlignment(4, 0); - } -}; +MCELFStreamer::~MCELFStreamer() { +} -} // end anonymous namespace. +void MCELFStreamer::InitToTextSection() { + SetSectionText(); +} void MCELFStreamer::InitSections() { // This emulates the same behavior of GNU as. This makes it easier @@ -161,132 +83,77 @@ void MCELFStreamer::InitSections() { void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - Symbol->setSection(*CurSection); + MCObjectStreamer::EmitLabel(Symbol); - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - - // 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(); + const MCSectionELF &Section = + static_cast(Symbol->getSection()); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + if (Section.getFlags() & ELF::SHF_TLS) + MCELF::SetType(SD, ELF::STT_TLS); +} - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); +void MCELFStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().handleAssemblerFlag(Flag); + // Do any generic stuff we need to do. switch (Flag) { - case MCAF_SyntaxUnified: return; // no-op here? + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // Change parsing mode; no-op here. + case MCAF_Code32: return; // Change parsing mode; no-op here. + case MCAF_Code64: return; // Change parsing mode; no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; } - assert(0 && "invalid assembler flag!"); + llvm_unreachable("invalid assembler flag!"); } -void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - // FIXME: Lift context changes into super class. - getAssembler().getOrCreateSymbolData(*Symbol); - 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::ChangeSection(const MCSection *Section, + const MCExpr *Subsection) { + MCSectionData *CurSection = getCurrentSectionData(); + if (CurSection && CurSection->isBundleLocked()) + report_fatal_error("Unterminated .bundle_lock when changing a section"); + const MCSymbol *Grp = static_cast(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::ChangeSection(Section, Subsection); +} 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()); + const MCExpr *Value = MCSymbolRefExpr::Create(Symbol, getContext()); Alias->setVariableValue(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)); -} - -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); +// When GNU as encounters more than one .type declaration for an object it seems +// to use a mechanism similar to the one below to decide which type is actually +// used in the object file. The greater of T1 and T2 is selected based on the +// following ordering: +// STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else +// If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user +// provided type). +static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) { + unsigned TypeOrdering[] = {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC, + ELF::STT_GNU_IFUNC, ELF::STT_TLS}; + for (unsigned i = 0; i != array_lengthof(TypeOrdering); ++i) { + if (T1 == TypeOrdering[i]) + return T2; + if (T2 == TypeOrdering[i]) + return T1; + } - uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STV_Shift); - SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); + return T2; } -void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, - MCSymbolAttr Attribute) { +bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { // Indirect symbols are handled differently, to match how 'as' handles // them. This makes writing matching .o files easier. if (Attribute == MCSA_IndirectSymbol) { @@ -296,7 +163,7 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, ISD.Symbol = Symbol; ISD.SectionData = getCurrentSectionData(); getAssembler().getIndirectSymbols().push_back(ISD); - return; + return true; } // Adding a symbol attribute always introduces the symbol, note that an @@ -313,67 +180,83 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, switch (Attribute) { case MCSA_LazyReference: case MCSA_Reference: - case MCSA_NoDeadStrip: + case MCSA_SymbolResolver: case MCSA_PrivateExtern: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: - case MCSA_ELF_TypeIndFunction: case MCSA_IndirectSymbol: - assert(0 && "Invalid symbol attribute for ELF!"); + return false; + + case MCSA_NoDeadStrip: + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. break; case MCSA_Global: - SetBinding(SD, ELF::STB_GLOBAL); + MCELF::SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); BindingExplicitlySet.insert(Symbol); break; case MCSA_WeakReference: case MCSA_Weak: - SetBinding(SD, ELF::STB_WEAK); + MCELF::SetBinding(SD, ELF::STB_WEAK); SD.setExternal(true); BindingExplicitlySet.insert(Symbol); break; case MCSA_Local: - SetBinding(SD, ELF::STB_LOCAL); + MCELF::SetBinding(SD, ELF::STB_LOCAL); SD.setExternal(false); BindingExplicitlySet.insert(Symbol); break; case MCSA_ELF_TypeFunction: - SetType(SD, ELF::STT_FUNC); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_FUNC)); + break; + + case MCSA_ELF_TypeIndFunction: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_GNU_IFUNC)); break; case MCSA_ELF_TypeObject: - SetType(SD, ELF::STT_OBJECT); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_OBJECT)); break; case MCSA_ELF_TypeTLS: - SetType(SD, ELF::STT_TLS); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_TLS)); break; case MCSA_ELF_TypeCommon: - SetType(SD, ELF::STT_COMMON); + // TODO: Emit these as a common symbol. + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_OBJECT)); break; case MCSA_ELF_TypeNoType: - SetType(SD, ELF::STT_NOTYPE); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_NOTYPE)); break; case MCSA_Protected: - SetVisibility(SD, ELF::STV_PROTECTED); + MCELF::SetVisibility(SD, ELF::STV_PROTECTED); break; case MCSA_Hidden: - SetVisibility(SD, ELF::STV_HIDDEN); + MCELF::SetVisibility(SD, ELF::STV_HIDDEN); break; case MCSA_Internal: - SetVisibility(SD, ELF::STV_INTERNAL); + MCELF::SetVisibility(SD, ELF::STV_INTERNAL); break; } + + return true; } void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -381,17 +264,20 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); if (!BindingExplicitlySet.count(Symbol)) { - SetBinding(SD, ELF::STB_GLOBAL); + MCELF::SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); } - if (GetBinding(SD) == ELF_STB_Local) { + MCELF::SetType(SD, ELF::STT_OBJECT); + + if (MCELF::GetBinding(SD) == ELF_STB_Local) { const MCSection *Section = getAssembler().getContext().getELFSection(".bss", - MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, - SectionKind::getBSS()); - Symbol->setSection(*Section); + ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, + SectionKind::getBSS()); + + AssignSection(Symbol, Section); struct LocalCommon L = {&SD, Size, ByteAlignment}; LocalCommons.push_back(L); @@ -402,115 +288,257 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, SD.setSize(MCConstantExpr::Create(Size, getContext())); } -void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +void MCELFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setSize(Value); } -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(); +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + // FIXME: Should this be caught and done earlier? + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + MCELF::SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + EmitCommonSymbol(Symbol, Size, ByteAlignment); +} - // 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::EmitValueImpl(const MCExpr *Value, unsigned Size) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); + fixSymbolsInTLSFixups(Value); + MCObjectStreamer::EmitValueImpl(Value, Size); } void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, - int64_t Value, unsigned ValueSize, - unsigned MaxBytesToEmit) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - if (MaxBytesToEmit == 0) - MaxBytesToEmit = ByteAlignment; - new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, - getCurrentSectionData()); - - // Update the maximum alignment on the current section if necessary. - if (ByteAlignment > getCurrentSectionData()->getAlignment()) - getCurrentSectionData()->setAlignment(ByteAlignment); -} - -void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - if (MaxBytesToEmit == 0) - MaxBytesToEmit = ByteAlignment; - MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, - getCurrentSectionData()); - F->setEmitNops(true); - - // Update the maximum alignment on the current section if necessary. - if (ByteAlignment > getCurrentSectionData()->getAlignment()) - 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). + int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); + MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, + ValueSize, MaxBytesToEmit); +} + +// Add a symbol for the file name of this module. They start after the +// null symbol and don't count as normal symbol, i.e. a non-STT_FILE symbol +// with the same name may appear. void MCELFStreamer::EmitFileDirective(StringRef Filename) { - MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename); - Symbol->setSection(*CurSection); - Symbol->setAbsolute(); + getAssembler().addFileName(Filename); +} - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); +void MCELFStreamer::EmitIdent(StringRef IdentString) { + const MCSection *Comment = getAssembler().getContext().getELFSection( + ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, + SectionKind::getReadOnly(), 1, ""); + PushSection(); + SwitchSection(Comment); + if (!SeenIdent) { + EmitIntValue(0, 1); + SeenIdent = true; + } + EmitBytes(IdentString); + EmitIntValue(0, 1); + PopSection(); +} + +void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { + switch (expr->getKind()) { + case MCExpr::Target: + cast(expr)->fixELFSymbolsInTLSFixups(getAssembler()); + break; + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *be = cast(expr); + fixSymbolsInTLSFixups(be->getLHS()); + fixSymbolsInTLSFixups(be->getRHS()); + break; + } - SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &symRef = *cast(expr); + switch (symRef.getKind()) { + default: + return; + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_INDNTPOFF: + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_TLSLD: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_Mips_TLSGD: + case MCSymbolRefExpr::VK_Mips_GOTTPREL: + case MCSymbolRefExpr::VK_Mips_TPREL_HI: + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + case MCSymbolRefExpr::VK_PPC_DTPMOD: + case MCSymbolRefExpr::VK_PPC_TPREL: + case MCSymbolRefExpr::VK_PPC_TPREL_LO: + case MCSymbolRefExpr::VK_PPC_TPREL_HI: + case MCSymbolRefExpr::VK_PPC_TPREL_HA: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA: + case MCSymbolRefExpr::VK_PPC_DTPREL: + case MCSymbolRefExpr::VK_PPC_DTPREL_LO: + case MCSymbolRefExpr::VK_PPC_DTPREL_HI: + case MCSymbolRefExpr::VK_PPC_DTPREL_HA: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA: + case MCSymbolRefExpr::VK_PPC_GOT_TPREL: + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI: + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA: + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI: + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA: + case MCSymbolRefExpr::VK_PPC_TLS: + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD: + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO: + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI: + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA: + case MCSymbolRefExpr::VK_PPC_TLSGD: + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD: + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO: + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI: + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA: + case MCSymbolRefExpr::VK_PPC_TLSLD: + break; + } + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(symRef.getSymbol()); + MCELF::SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixSymbolsInTLSFixups(cast(expr)->getSubExpr()); + break; + } } void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + this->MCObjectStreamer::EmitInstToFragment(Inst); + MCRelaxableFragment &F = *cast(getCurrentFragment()); - // 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 Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); - VecOS.flush(); - - 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) { - MCDataFragment *DF = getOrCreateDataFragment(); - + MCAssembler &Assembler = getAssembler(); SmallVector Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + fixSymbolsInTLSFixups(Fixups[i].getValue()); + + // There are several possibilities here: + // + // If bundling is disabled, append the encoded instruction to the current data + // fragment (or create a new such fragment if the current fragment is not a + // data fragment). + // + // If bundling is enabled: + // - If we're not in a bundle-locked group, emit the instruction into a + // fragment of its own. If there are no fixups registered for the + // instruction, emit a MCCompactEncodedInstFragment. Otherwise, emit a + // MCDataFragment. + // - If we're in a bundle-locked group, append the instruction to the current + // data fragment because we want all the instructions in a group to get into + // the same fragment. Be careful not to do that for the first instruction in + // the group, though. + MCDataFragment *DF; + + if (Assembler.isBundlingEnabled()) { + MCSectionData *SD = getCurrentSectionData(); + if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst()) + // If we are bundle-locked, we re-use the current fragment. + // The bundle-locking directive ensures this is a new data fragment. + DF = cast(getCurrentFragment()); + else if (!SD->isBundleLocked() && Fixups.size() == 0) { + // Optimize memory usage by emitting the instruction to a + // MCCompactEncodedInstFragment when not in a bundle-locked group and + // there are no fixups registered. + MCCompactEncodedInstFragment *CEIF = new MCCompactEncodedInstFragment(); + insert(CEIF); + CEIF->getContents().append(Code.begin(), Code.end()); + return; + } else { + DF = new MCDataFragment(); + insert(DF); + if (SD->getBundleLockState() == MCSectionData::BundleLockedAlignToEnd) { + // If this is a new fragment created for a bundle-locked group, and the + // group was marked as "align_to_end", set a flag in the fragment. + DF->setAlignToBundleEnd(true); + } + } + + // We're now emitting an instruction in a bundle group, so this flag has + // to be turned off. + SD->setBundleGroupBeforeFirstInst(false); + } else { + DF = getOrCreateDataFragment(); + } + // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); - DF->addFixup(Fixups[i]); + DF->getFixups().push_back(Fixups[i]); } + DF->setHasInstructions(true); DF->getContents().append(Code.begin(), Code.end()); } -void MCELFStreamer::Finish() { +void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { + assert(AlignPow2 <= 30 && "Invalid bundle alignment"); + MCAssembler &Assembler = getAssembler(); + if (Assembler.getBundleAlignSize() == 0 && AlignPow2 > 0) + Assembler.setBundleAlignSize(1 << AlignPow2); + else + report_fatal_error(".bundle_align_mode should be only set once per file"); +} + +void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + // + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_lock forbidden when bundling is disabled"); + else if (SD->isBundleLocked()) + report_fatal_error("Nesting of .bundle_lock is forbidden"); + + SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd : + MCSectionData::BundleLocked); + SD->setBundleGroupBeforeFirstInst(true); +} + +void MCELFStreamer::EmitBundleUnlock() { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_unlock forbidden when bundling is disabled"); + else if (!SD->isBundleLocked()) + report_fatal_error(".bundle_unlock without matching lock"); + else if (SD->isBundleGroupBeforeFirstInst()) + report_fatal_error("Empty bundle-locked group is forbidden"); + + SD->setBundleLockState(MCSectionData::NotBundleLocked); +} + +void MCELFStreamer::Flush() { for (std::vector::const_iterator i = LocalCommons.begin(), e = LocalCommons.end(); i != e; ++i) { @@ -531,14 +559,64 @@ void MCELFStreamer::Finish() { SectData.setAlignment(ByteAlignment); } - this->MCObjectStreamer::Finish(); + LocalCommons.clear(); +} + +void MCELFStreamer::FinishImpl() { + EmitFrames(NULL, true); + + Flush(); + + this->MCObjectStreamer::FinishImpl(); } -MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll) { - MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); +MCStreamer *llvm::createELFStreamer(MCContext &Context, + MCTargetStreamer *Streamer, + MCAsmBackend &MAB, raw_ostream &OS, + MCCodeEmitter *CE, bool RelaxAll, + bool NoExecStack) { + MCELFStreamer *S = new MCELFStreamer(Context, Streamer, MAB, OS, CE); if (RelaxAll) S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); return S; } + +void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("Generic ELF doesn't support this directive"); +} + +MCSymbolData &MCELFStreamer::getOrCreateSymbolData(MCSymbol *Symbol) { + return getAssembler().getOrCreateSymbolData(*Symbol); +} + +void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolType(int Type) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EndCOFFSymbolDef() { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +}