-//===- 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"
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.
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);
}
+// 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;
+}
+
void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
MCSymbolAttr Attribute) {
// Indirect symbols are handled differently, to match how 'as' handles
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:
// 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_TPREL16_HA:
+ case MCSymbolRefExpr::VK_PPC_TPREL16_LO:
+ case MCSymbolRefExpr::VK_PPC_DTPREL16_HA:
+ case MCSymbolRefExpr::VK_PPC_DTPREL16_LO:
+ case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_HA:
+ case MCSymbolRefExpr::VK_PPC_GOT_TPREL16_LO:
+ case MCSymbolRefExpr::VK_PPC_TLS:
+ case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_HA:
+ case MCSymbolRefExpr::VK_PPC_GOT_TLSGD16_LO:
+ case MCSymbolRefExpr::VK_PPC_TLSGD:
+ case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_HA:
+ case MCSymbolRefExpr::VK_PPC_GOT_TLSLD16_LO:
+ 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.
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");
}