-//===- lib/MC/MCELFStreamer.cpp - ELF Object Output ------------===//
+//===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===//
//
// The LLVM Compiler Infrastructure
//
#include "llvm/MC/MCELFStreamer.h"
#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
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<const MCSectionELF *>(Section)->getGroup();
if (Grp)
getAssembler().getOrCreateSymbolData(*Grp);
- this->MCObjectStreamer::ChangeSection(Section);
+ this->MCObjectStreamer::ChangeSection(Section, Subsection);
}
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) {
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
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:
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:
MCELF::SetVisibility(SD, ELF::STV_INTERNAL);
break;
}
+
+ return true;
}
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);
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,
// 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(*getCurrentSection());
+ Symbol->setSection(*getCurrentSection().first);
Symbol->setAbsolute();
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) {
switch (expr->getKind()) {
- case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!");
+ case MCExpr::Target:
+ cast<MCTargetExpr>(expr)->fixELFSymbolsInTLSFixups(getAssembler());
+ break;
case MCExpr::Constant:
break;
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());
// 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
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<MCDataFragment>(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.
SD->setBundleLockState(MCSectionData::NotBundleLocked);
}
-void MCELFStreamer::FinishImpl() {
- EmitFrames(true);
-
+void MCELFStreamer::Flush() {
for (std::vector<LocalCommon>::const_iterator i = LocalCommons.begin(),
e = LocalCommons.end();
i != e; ++i) {
SectData.setAlignment(ByteAlignment);
}
- this->MCObjectStreamer::FinishImpl();
+ LocalCommons.clear();
}
-void MCELFStreamer::EmitTCEntry(const MCSymbol &S) {
- // Creates a R_PPC64_TOC relocation
- MCObjectStreamer::EmitSymbolValue(&S, 8);
+
+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)
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");
}