X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FMC%2FMCELFStreamer.cpp;h=180a58cf6d144df6c268af98eed5730c12013766;hb=6e08a410aa0a375450dfbdd3c1114aafc5fb1fb9;hp=e3acc44a859346d8e83f67c79cbddf352d99ebf2;hpb=4766ef41b31e4f97bce1179c3b0398303bf65356;p=oota-llvm.git diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index e3acc44a859..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 // @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #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/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -65,6 +67,10 @@ inline void MCELFStreamer::SetSectionBss() { MCELFStreamer::~MCELFStreamer() { } +void MCELFStreamer::InitToTextSection() { + SetSectionText(); +} + 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. @@ -91,6 +97,9 @@ void MCELFStreamer::EmitDebugLabel(MCSymbol *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_Code16: return; // Change parsing mode; no-op here. @@ -104,14 +113,15 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { llvm_unreachable("invalid assembler flag!"); } -void MCELFStreamer::ChangeSection(const MCSection *Section) { +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); + this->MCObjectStreamer::ChangeSection(Section, Subsection); } void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { @@ -122,8 +132,28 @@ void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { Alias->setVariableValue(Value); } -void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, - MCSymbolAttr Attribute) { +// 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; + } + + return T2; +} + +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) { @@ -133,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 @@ -156,7 +186,7 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: case MCSA_IndirectSymbol: - llvm_unreachable("Invalid symbol attribute for ELF!"); + return false; case MCSA_NoDeadStrip: case MCSA_ELF_TypeGnuUniqueObject: @@ -183,27 +213,34 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, break; case MCSA_ELF_TypeFunction: - MCELF::SetType(SD, ELF::STT_FUNC); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_FUNC)); break; case MCSA_ELF_TypeIndFunction: - MCELF::SetType(SD, ELF::STT_GNU_IFUNC); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_GNU_IFUNC)); break; case MCSA_ELF_TypeObject: - MCELF::SetType(SD, ELF::STT_OBJECT); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_OBJECT)); break; case MCSA_ELF_TypeTLS: - MCELF::SetType(SD, ELF::STT_TLS); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_TLS)); break; case MCSA_ELF_TypeCommon: - MCELF::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: - MCELF::SetType(SD, ELF::STT_NOTYPE); + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_NOTYPE)); break; case MCSA_Protected: @@ -218,6 +255,8 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCELF::SetVisibility(SD, ELF::STV_INTERNAL); break; } + + return true; } void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, @@ -237,7 +276,8 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, ELF::SHF_WRITE | ELF::SHF_ALLOC, SectionKind::getBSS()); - Symbol->setSection(*Section); + + AssignSection(Symbol, Section); struct LocalCommon L = {&SD, Size, ByteAlignment}; LocalCommons.push_back(L); @@ -263,12 +303,11 @@ void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, EmitCommonSymbol(Symbol, Size, ByteAlignment); } -void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { +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, AddrSpace); + MCObjectStreamer::EmitValueImpl(Value, Size); } void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, @@ -281,22 +320,33 @@ void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, ValueSize, MaxBytesToEmit); } - -// 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). +// 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(*getCurrentSection()); - Symbol->setAbsolute(); - - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - - SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); + getAssembler().addFileName(Filename); +} + +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) { +void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { switch (expr->getKind()) { - case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Target: + cast(expr)->fixELFSymbolsInTLSFixups(getAssembler()); + break; case MCExpr::Constant: break; @@ -321,13 +371,46 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { case MCSymbolRefExpr::VK_TLSLDM: case MCSymbolRefExpr::VK_TPOFF: case MCSymbolRefExpr::VK_DTPOFF: - case MCSymbolRefExpr::VK_ARM_TLSGD: - case MCSymbolRefExpr::VK_ARM_TPOFF: - case MCSymbolRefExpr::VK_ARM_GOTTPOFF: 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()); @@ -343,7 +426,7 @@ void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { this->MCObjectStreamer::EmitInstToFragment(Inst); - MCInstFragment &F = *cast(getCurrentFragment()); + MCRelaxableFragment &F = *cast(getCurrentFragment()); for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); @@ -367,8 +450,10 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { // data fragment). // // If bundling is enabled: - // - If we're not in a bundle-locked group, emit the instruction into a data - // fragment of its own. + // - 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 @@ -378,9 +463,26 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { if (Assembler.isBundlingEnabled()) { MCSectionData *SD = getCurrentSectionData(); if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst()) - DF = getOrCreateDataFragment(); - else - DF = new MCDataFragment(SD); + // 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. @@ -407,7 +509,7 @@ void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { report_fatal_error(".bundle_align_mode should be only set once per file"); } -void MCELFStreamer::EmitBundleLock() { +void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { MCSectionData *SD = getCurrentSectionData(); // Sanity checks @@ -417,7 +519,8 @@ void MCELFStreamer::EmitBundleLock() { else if (SD->isBundleLocked()) report_fatal_error("Nesting of .bundle_lock is forbidden"); - SD->setBundleLocked(true); + SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd : + MCSectionData::BundleLocked); SD->setBundleGroupBeforeFirstInst(true); } @@ -432,12 +535,10 @@ void MCELFStreamer::EmitBundleUnlock() { else if (SD->isBundleGroupBeforeFirstInst()) report_fatal_error("Empty bundle-locked group is forbidden"); - SD->setBundleLocked(false); + SD->setBundleLockState(MCSectionData::NotBundleLocked); } -void MCELFStreamer::FinishImpl() { - EmitFrames(true); - +void MCELFStreamer::Flush() { for (std::vector::const_iterator i = LocalCommons.begin(), e = LocalCommons.end(); i != e; ++i) { @@ -458,17 +559,23 @@ void MCELFStreamer::FinishImpl() { SectData.setAlignment(ByteAlignment); } - this->MCObjectStreamer::FinishImpl(); + LocalCommons.clear(); } -void MCELFStreamer::EmitTCEntry(const MCSymbol &S) { - // Creates a R_PPC64_TOC relocation - MCObjectStreamer::EmitSymbolValue(&S, 8, 0); + +void MCELFStreamer::FinishImpl() { + EmitFrames(NULL, true); + + Flush(); + + this->MCObjectStreamer::FinishImpl(); } -MCStreamer *llvm::createELFStreamer(MCContext &Context, MCAsmBackend &MAB, - raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll, bool NoExecStack) { - MCELFStreamer *S = new MCELFStreamer(Context, MAB, 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) @@ -480,6 +587,10 @@ 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"); }