summaryrefslogtreecommitdiffstats
path: root/lib/MC
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MC')
-rw-r--r--lib/MC/CMakeLists.txt3
-rw-r--r--lib/MC/MCAsmInfo.cpp1
-rw-r--r--lib/MC/MCAsmInfoDarwin.cpp1
-rw-r--r--lib/MC/MCAsmStreamer.cpp59
-rw-r--r--lib/MC/MCAssembler.cpp673
-rw-r--r--lib/MC/MCContext.cpp53
-rw-r--r--lib/MC/MCExpr.cpp14
-rw-r--r--lib/MC/MCInst.cpp2
-rw-r--r--lib/MC/MCLabel.cpp21
-rw-r--r--lib/MC/MCLoggingStreamer.cpp208
-rw-r--r--lib/MC/MCMachOStreamer.cpp226
-rw-r--r--lib/MC/MCNullStreamer.cpp9
-rw-r--r--lib/MC/MCParser/AsmLexer.cpp12
-rw-r--r--lib/MC/MCParser/AsmParser.cpp251
-rw-r--r--lib/MC/MCSection.cpp27
-rw-r--r--lib/MC/MCSectionCOFF.cpp76
-rw-r--r--lib/MC/MCSectionMachO.cpp11
-rw-r--r--lib/MC/MCStreamer.cpp2
-rw-r--r--lib/MC/MCSymbol.cpp12
-rw-r--r--lib/MC/MachObjectWriter.cpp201
20 files changed, 1296 insertions, 566 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt
index dba0e14..5e8a3b6 100644
--- a/lib/MC/CMakeLists.txt
+++ b/lib/MC/CMakeLists.txt
@@ -10,10 +10,13 @@ add_llvm_library(LLVMMC
MCExpr.cpp
MCInst.cpp
MCInstPrinter.cpp
+ MCLabel.cpp
+ MCLoggingStreamer.cpp
MCMachOStreamer.cpp
MCNullStreamer.cpp
MCObjectWriter.cpp
MCSection.cpp
+ MCSectionCOFF.cpp
MCSectionELF.cpp
MCSectionMachO.cpp
MCStreamer.cpp
diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp
index 2b23994..a275be2 100644
--- a/lib/MC/MCAsmInfo.cpp
+++ b/lib/MC/MCAsmInfo.cpp
@@ -21,6 +21,7 @@ using namespace llvm;
MCAsmInfo::MCAsmInfo() {
HasSubsectionsViaSymbols = false;
HasMachoZeroFillDirective = false;
+ HasMachoTBSSDirective = false;
HasStaticCtorDtorReferenceInStaticMode = false;
MaxInstLength = 4;
PCSymbol = "$";
diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp
index 3c31caa..0bd3b2d 100644
--- a/lib/MC/MCAsmInfoDarwin.cpp
+++ b/lib/MC/MCAsmInfoDarwin.cpp
@@ -35,6 +35,7 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() {
WeakRefDirective = "\t.weak_reference ";
ZeroDirective = "\t.space\t"; // ".space N" emits N zeros.
HasMachoZeroFillDirective = true; // Uses .zerofill
+ HasMachoTBSSDirective = true; // Uses .tbss
HasStaticCtorDtorReferenceInStaticMode = true;
HiddenVisibilityAttr = MCSA_PrivateExtern;
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 2c7e1c4..57b2bcc 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -109,7 +109,10 @@ public:
virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
-
+ virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol);
+ virtual void EmitCOFFSymbolStorageClass(int StorageClass);
+ virtual void EmitCOFFSymbolType(int Type);
+ virtual void EndCOFFSymbolDef();
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value);
virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment);
@@ -123,6 +126,9 @@ public:
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 0);
+ virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment = 0);
+
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
@@ -218,6 +224,7 @@ void MCAsmStreamer::SwitchSection(const MCSection *Section) {
void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
+ assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
assert(CurSection && "Cannot emit before setting section!");
OS << *Symbol << ":";
@@ -234,16 +241,11 @@ void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
}
void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
- // Only absolute symbols can be redefined.
- assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
- "Cannot define a symbol twice!");
-
OS << *Symbol << " = " << *Value;
EmitEOL();
// FIXME: Lift context changes into super class.
- // FIXME: Set associated section.
- Symbol->setValue(Value);
+ Symbol->setVariableValue(Value);
}
void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
@@ -297,6 +299,26 @@ void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
EmitEOL();
}
+void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) {
+ OS << "\t.def\t " << *Symbol << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) {
+ OS << "\t.scl\t" << StorageClass << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSymbolType (int Type) {
+ OS << "\t.type\t" << Type << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EndCOFFSymbolDef() {
+ OS << "\t.endef";
+ EmitEOL();
+}
+
void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
assert(MAI.hasDotTypeDotSizeDirective());
OS << "\t.size\t" << *Symbol << ", " << *Value << '\n';
@@ -341,6 +363,23 @@ void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
EmitEOL();
}
+// .tbss sym, size, align
+// This depends that the symbol has already been mangled from the original,
+// e.g. _a.
+void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ assert(Symbol != NULL && "Symbol shouldn't be NULL!");
+ // Instead of using the Section we'll just use the shortcut.
+ // This is a mach-o specific directive and section.
+ OS << ".tbss " << *Symbol << ", " << Size;
+
+ // Output align if we have it. We default to 1 so don't bother printing
+ // that.
+ if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment);
+
+ EmitEOL();
+}
+
static inline char toOctal(int X) { return (X&7)+'0'; }
static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
@@ -630,9 +669,11 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
AddEncodingComment(Inst);
// Show the MCInst if enabled.
- if (ShowInst)
+ if (ShowInst) {
Inst.dump_pretty(GetCommentOS(), &MAI, InstPrinter.get(), "\n ");
-
+ GetCommentOS() << "\n";
+ }
+
// If we have an AsmPrinter, use that to print, otherwise print the MCInst.
if (InstPrinter)
InstPrinter->printInst(&Inst, OS);
diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp
index 69afcc8..5936656 100644
--- a/lib/MC/MCAssembler.cpp
+++ b/lib/MC/MCAssembler.cpp
@@ -47,93 +47,131 @@ STATISTIC(SectionLayouts, "Number of section layouts");
/* *** */
-void MCAsmLayout::UpdateForSlide(MCFragment *F, int SlideAmount) {
- // We shouldn't have to do anything special to support negative slides, and it
- // is a perfectly valid thing to do as long as other parts of the system are
- // can guarantee convergence.
- assert(SlideAmount >= 0 && "Negative slides not yet supported");
+MCAsmLayout::MCAsmLayout(MCAssembler &Asm)
+ : Assembler(Asm), LastValidFragment(0)
+ {
+ // Compute the section layout order. Virtual sections must go last.
+ for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
+ if (!Asm.getBackend().isVirtualSection(it->getSection()))
+ SectionOrder.push_back(&*it);
+ for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
+ if (Asm.getBackend().isVirtualSection(it->getSection()))
+ SectionOrder.push_back(&*it);
+}
- // Update the layout by simply recomputing the layout for the entire
- // file. This is trivially correct, but very slow.
- //
- // FIXME-PERF: This is O(N^2), but will be eliminated once we get smarter.
+bool MCAsmLayout::isSectionUpToDate(const MCSectionData *SD) const {
+ // The first section is always up-to-date.
+ unsigned Index = SD->getLayoutOrder();
+ if (!Index)
+ return true;
- // Layout the concrete sections and fragments.
- MCAssembler &Asm = getAssembler();
- uint64_t Address = 0;
- for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) {
- // Skip virtual sections.
- if (Asm.getBackend().isVirtualSection(it->getSection()))
- continue;
+ // Otherwise, sections are always implicitly computed when the preceeding
+ // fragment is layed out.
+ const MCSectionData *Prev = getSectionOrder()[Index - 1];
+ return isFragmentUpToDate(&(Prev->getFragmentList().back()));
+}
+
+bool MCAsmLayout::isFragmentUpToDate(const MCFragment *F) const {
+ return (LastValidFragment &&
+ F->getLayoutOrder() <= LastValidFragment->getLayoutOrder());
+}
- // Layout the section fragments and its size.
- Address = Asm.LayoutSection(*it, *this, Address);
+void MCAsmLayout::UpdateForSlide(MCFragment *F, int SlideAmount) {
+ // If this fragment wasn't already up-to-date, we don't need to do anything.
+ if (!isFragmentUpToDate(F))
+ return;
+
+ // Otherwise, reset the last valid fragment to the predecessor of the
+ // invalidated fragment.
+ LastValidFragment = F->getPrevNode();
+ if (!LastValidFragment) {
+ unsigned Index = F->getParent()->getLayoutOrder();
+ if (Index != 0) {
+ MCSectionData *Prev = getSectionOrder()[Index - 1];
+ LastValidFragment = &(Prev->getFragmentList().back());
+ }
}
+}
- // Layout the virtual sections.
- for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) {
- if (!Asm.getBackend().isVirtualSection(it->getSection()))
- continue;
+void MCAsmLayout::EnsureValid(const MCFragment *F) const {
+ // Advance the layout position until the fragment is up-to-date.
+ while (!isFragmentUpToDate(F)) {
+ // Advance to the next fragment.
+ MCFragment *Cur = LastValidFragment;
+ if (Cur)
+ Cur = Cur->getNextNode();
+ if (!Cur) {
+ unsigned NextIndex = 0;
+ if (LastValidFragment)
+ NextIndex = LastValidFragment->getParent()->getLayoutOrder() + 1;
+ Cur = SectionOrder[NextIndex]->begin();
+ }
- // Layout the section fragments and its size.
- Address = Asm.LayoutSection(*it, *this, Address);
+ const_cast<MCAsmLayout*>(this)->LayoutFragment(Cur);
}
}
+void MCAsmLayout::FragmentReplaced(MCFragment *Src, MCFragment *Dst) {
+ if (LastValidFragment == Src)
+ LastValidFragment = Dst;
+
+ Dst->Offset = Src->Offset;
+ Dst->EffectiveSize = Src->EffectiveSize;
+}
+
uint64_t MCAsmLayout::getFragmentAddress(const MCFragment *F) const {
assert(F->getParent() && "Missing section()!");
return getSectionAddress(F->getParent()) + getFragmentOffset(F);
}
uint64_t MCAsmLayout::getFragmentEffectiveSize(const MCFragment *F) const {
+ EnsureValid(F);
assert(F->EffectiveSize != ~UINT64_C(0) && "Address not set!");
return F->EffectiveSize;
}
-void MCAsmLayout::setFragmentEffectiveSize(MCFragment *F, uint64_t Value) {
- F->EffectiveSize = Value;
-}
-
uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const {
+ EnsureValid(F);
assert(F->Offset != ~UINT64_C(0) && "Address not set!");
return F->Offset;
}
-void MCAsmLayout::setFragmentOffset(MCFragment *F, uint64_t Value) {
- F->Offset = Value;
-}
-
uint64_t MCAsmLayout::getSymbolAddress(const MCSymbolData *SD) const {
assert(SD->getFragment() && "Invalid getAddress() on undefined symbol!");
return getFragmentAddress(SD->getFragment()) + SD->getOffset();
}
uint64_t MCAsmLayout::getSectionAddress(const MCSectionData *SD) const {
+ EnsureValid(SD->begin());
assert(SD->Address != ~UINT64_C(0) && "Address not set!");
return SD->Address;
}
-void MCAsmLayout::setSectionAddress(MCSectionData *SD, uint64_t Value) {
- SD->Address = Value;
-}
-
-uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const {
- assert(SD->Size != ~UINT64_C(0) && "File size not set!");
- return SD->Size;
-}
-void MCAsmLayout::setSectionSize(MCSectionData *SD, uint64_t Value) {
- SD->Size = Value;
+uint64_t MCAsmLayout::getSectionAddressSize(const MCSectionData *SD) const {
+ // The size is the last fragment's end offset.
+ const MCFragment &F = SD->getFragmentList().back();
+ return getFragmentOffset(&F) + getFragmentEffectiveSize(&F);
}
uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const {
- assert(SD->FileSize != ~UINT64_C(0) && "File size not set!");
- return SD->FileSize;
-}
-void MCAsmLayout::setSectionFileSize(MCSectionData *SD, uint64_t Value) {
- SD->FileSize = Value;
+ // Virtual sections have no file size.
+ if (getAssembler().getBackend().isVirtualSection(SD->getSection()))
+ return 0;
+
+ // Otherwise, the file size is the same as the address space size.
+ return getSectionAddressSize(SD);
}
- /// @}
+uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const {
+ // The logical size is the address space size minus any tail padding.
+ uint64_t Size = getSectionAddressSize(SD);
+ const MCAlignFragment *AF =
+ dyn_cast<MCAlignFragment>(&(SD->getFragmentList().back()));
+ if (AF && AF->hasOnlyAlignAddress())
+ Size -= getFragmentEffectiveSize(AF);
+
+ return Size;
+}
/* *** */
@@ -141,17 +179,12 @@ MCFragment::MCFragment() : Kind(FragmentType(~0)) {
}
MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent)
- : Kind(_Kind),
- Parent(_Parent),
- EffectiveSize(~UINT64_C(0))
+ : Kind(_Kind), Parent(_Parent), Atom(0), EffectiveSize(~UINT64_C(0))
{
if (Parent)
Parent->getFragmentList().push_back(this);
}
-MCFragment::~MCFragment() {
-}
-
/* *** */
MCSectionData::MCSectionData() : Section(0) {}
@@ -160,8 +193,6 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(&_Section),
Alignment(1),
Address(~UINT64_C(0)),
- Size(~UINT64_C(0)),
- FileSize(~UINT64_C(0)),
HasInstructions(false)
{
if (A)
@@ -195,7 +226,7 @@ MCAssembler::~MCAssembler() {
}
static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm,
- const MCAsmFixup &Fixup,
+ const MCFixup &Fixup,
const MCValue Target,
const MCSection *BaseSection) {
// The effective fixup address is
@@ -233,7 +264,7 @@ static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm,
static bool isScatteredFixupFullyResolved(const MCAssembler &Asm,
const MCAsmLayout &Layout,
- const MCAsmFixup &Fixup,
+ const MCFixup &Fixup,
const MCValue Target,
const MCSymbolData *BaseSymbol) {
// The effective fixup address is
@@ -291,36 +322,6 @@ bool MCAssembler::isSymbolLinkerVisible(const MCSymbolData *SD) const {
SD->getFragment()->getParent()->getSection());
}
-// FIXME-PERF: This routine is really slow.
-const MCSymbolData *MCAssembler::getAtomForAddress(const MCAsmLayout &Layout,
- const MCSectionData *Section,
- uint64_t Address) const {
- const MCSymbolData *Best = 0;
- uint64_t BestAddress = 0;
-
- for (MCAssembler::const_symbol_iterator it = symbol_begin(),
- ie = symbol_end(); it != ie; ++it) {
- // Ignore non-linker visible symbols.
- if (!isSymbolLinkerVisible(it))
- continue;
-
- // Ignore symbols not in the same section.
- if (!it->getFragment() || it->getFragment()->getParent() != Section)
- continue;
-
- // Otherwise, find the closest symbol preceding this address (ties are
- // resolved in favor of the last defined symbol).
- uint64_t SymbolAddress = Layout.getSymbolAddress(it);
- if (SymbolAddress <= Address && (!Best || SymbolAddress >= BestAddress)) {
- Best = it;
- BestAddress = SymbolAddress;
- }
- }
-
- return Best;
-}
-
-// FIXME-PERF: This routine is really slow.
const MCSymbolData *MCAssembler::getAtom(const MCAsmLayout &Layout,
const MCSymbolData *SD) const {
// Linker visible symbols define atoms.
@@ -331,17 +332,22 @@ const MCSymbolData *MCAssembler::getAtom(const MCAsmLayout &Layout,
if (!SD->getFragment())
return 0;
- // Otherwise, search by address.
- return getAtomForAddress(Layout, SD->getFragment()->getParent(),
- Layout.getSymbolAddress(SD));
+ // Non-linker visible symbols in sections which can't be atomized have no
+ // defining atom.
+ if (!getBackend().isSectionAtomizable(
+ SD->getFragment()->getParent()->getSection()))
+ return 0;
+
+ // Otherwise, return the atom for the containing fragment.
+ return SD->getFragment()->getAtom();
}
bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
- const MCAsmFixup &Fixup, const MCFragment *DF,
+ const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) const {
++stats::EvaluateFixup;
- if (!Fixup.Value->EvaluateAsRelocatable(Target, &Layout))
+ if (!Fixup.getValue()->EvaluateAsRelocatable(Target, &Layout))
report_fatal_error("expected relocatable expression");
// FIXME: How do non-scattered symbols work in ELF? I presume the linker
@@ -350,8 +356,8 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
Value = Target.getConstant();
- bool IsPCRel =
- Emitter.getFixupKindInfo(Fixup.Kind).Flags & MCFixupKindInfo::FKF_IsPCRel;
+ bool IsPCRel = Emitter.getFixupKindInfo(
+ Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel;
bool IsResolved = true;
if (const MCSymbolRefExpr *A = Target.getSymA()) {
if (A->getSymbol().isDefined())
@@ -374,8 +380,7 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
// symbol) that the fixup value is relative to.
const MCSymbolData *BaseSymbol = 0;
if (IsPCRel) {
- BaseSymbol = getAtomForAddress(
- Layout, DF->getParent(), Layout.getFragmentAddress(DF)+Fixup.Offset);
+ BaseSymbol = DF->getAtom();
if (!BaseSymbol)
IsResolved = false;
}
@@ -394,117 +399,123 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
}
if (IsPCRel)
- Value -= Layout.getFragmentAddress(DF) + Fixup.Offset;
+ Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset();
return IsResolved;
}
-uint64_t MCAssembler::LayoutSection(MCSectionData &SD,
- MCAsmLayout &Layout,
- uint64_t StartAddress) {
- bool IsVirtual = getBackend().isVirtualSection(SD.getSection());
-
- ++stats::SectionLayouts;
-
- // Align this section if necessary by adding padding bytes to the previous
- // section. It is safe to adjust this out-of-band, because no symbol or
- // fragment is allowed to point past the end of the section at any time.
- if (uint64_t Pad = OffsetToAlignment(StartAddress, SD.getAlignment())) {
- // Unless this section is virtual (where we are allowed to adjust the offset
- // freely), the padding goes in the previous section.
- if (!IsVirtual) {
- // Find the previous non-virtual section.
- iterator it = &SD;
- assert(it != begin() && "Invalid initial section address!");
- for (--it; getBackend().isVirtualSection(it->getSection()); --it) ;
- Layout.setSectionFileSize(&*it, Layout.getSectionFileSize(&*it) + Pad);
- }
+uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout,
+ const MCFragment &F,
+ uint64_t SectionAddress,
+ uint64_t FragmentOffset) const {
+ switch (F.getKind()) {
+ case MCFragment::FT_Data:
+ return cast<MCDataFragment>(F).getContents().size();
+ case MCFragment::FT_Fill:
+ return cast<MCFillFragment>(F).getSize();
+ case MCFragment::FT_Inst:
+ return cast<MCInstFragment>(F).getInstSize();
- StartAddress += Pad;
- }
+ case MCFragment::FT_Align: {
+ const MCAlignFragment &AF = cast<MCAlignFragment>(F);
- // Set the aligned section address.
- Layout.setSectionAddress(&SD, StartAddress);
+ assert((!AF.hasOnlyAlignAddress() || !AF.getNextNode()) &&
+ "Invalid OnlyAlignAddress bit, not the last fragment!");
- uint64_t Address = StartAddress;
- for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
- MCFragment &F = *it;
+ uint64_t Size = OffsetToAlignment(SectionAddress + FragmentOffset,
+ AF.getAlignment());
- ++stats::FragmentLayouts;
+ // Honor MaxBytesToEmit.
+ if (Size > AF.getMaxBytesToEmit())
+ return 0;
- uint64_t FragmentOffset = Address - StartAddress;
- Layout.setFragmentOffset(&F, FragmentOffset);
+ return Size;
+ }
- // Evaluate fragment size.
- uint64_t EffectiveSize = 0;
- switch (F.getKind()) {
- case MCFragment::FT_Align: {
- MCAlignFragment &AF = cast<MCAlignFragment>(F);
+ case MCFragment::FT_Org: {
+ const MCOrgFragment &OF = cast<MCOrgFragment>(F);
- EffectiveSize = OffsetToAlignment(Address, AF.getAlignment());
- if (EffectiveSize > AF.getMaxBytesToEmit())
- EffectiveSize = 0;
- break;
- }
+ // FIXME: We should compute this sooner, we don't want to recurse here, and
+ // we would like to be more functional.
+ int64_t TargetLocation;
+ if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout))
+ report_fatal_error("expected assembly-time absolute expression");
- case MCFragment::FT_Data:
- EffectiveSize = cast<MCDataFragment>(F).getContents().size();
- break;
+ // FIXME: We need a way to communicate this error.
+ int64_t Offset = TargetLocation - FragmentOffset;
+ if (Offset < 0)
+ report_fatal_error("invalid .org offset '" + Twine(TargetLocation) +
+ "' (at offset '" + Twine(FragmentOffset) + "'");
- case MCFragment::FT_Fill: {
- MCFillFragment &FF = cast<MCFillFragment>(F);
- EffectiveSize = FF.getValueSize() * FF.getCount();
- break;
- }
+ return Offset;
+ }
+ }
- case MCFragment::FT_Inst:
- EffectiveSize = cast<MCInstFragment>(F).getInstSize();
- break;
+ assert(0 && "invalid fragment kind");
+ return 0;
+}
- case MCFragment::FT_Org: {
- MCOrgFragment &OF = cast<MCOrgFragment>(F);
+void MCAsmLayout::LayoutFile() {
+ // Initialize the first section and set the valid fragment layout point. All
+ // actual layout computations are done lazily.
+ LastValidFragment = 0;
+ if (!getSectionOrder().empty())
+ getSectionOrder().front()->Address = 0;
+}
- int64_t TargetLocation;
- if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout))
- report_fatal_error("expected assembly-time absolute expression");
+void MCAsmLayout::LayoutFragment(MCFragment *F) {
+ MCFragment *Prev = F->getPrevNode();
- // FIXME: We need a way to communicate this error.
- int64_t Offset = TargetLocation - FragmentOffset;
- if (Offset < 0)
- report_fatal_error("invalid .org offset '" + Twine(TargetLocation) +
- "' (at offset '" + Twine(FragmentOffset) + "'");
+ // We should never try to recompute something which is up-to-date.
+ assert(!isFragmentUpToDate(F) && "Attempt to recompute up-to-date fragment!");
+ // We should never try to compute the fragment layout if the section isn't
+ // up-to-date.
+ assert(isSectionUpToDate(F->getParent()) &&
+ "Attempt to compute fragment before it's section!");
+ // We should never try to compute the fragment layout if it's predecessor
+ // isn't up-to-date.
+ assert((!Prev || isFragmentUpToDate(Prev)) &&
+ "Attempt to compute fragment before it's predecessor!");
- EffectiveSize = Offset;
- break;
- }
+ ++stats::FragmentLayouts;
- case MCFragment::FT_ZeroFill: {
- MCZeroFillFragment &ZFF = cast<MCZeroFillFragment>(F);
+ // Compute the fragment start address.
+ uint64_t StartAddress = F->getParent()->Address;
+ uint64_t Address = StartAddress;
+ if (Prev)
+ Address += Prev->Offset + Prev->EffectiveSize;
+
+ // Compute fragment offset and size.
+ F->Offset = Address - StartAddress;
+ F->EffectiveSize = getAssembler().ComputeFragmentSize(*this, *F, StartAddress,
+ F->Offset);
+ LastValidFragment = F;
+
+ // If this is the last fragment in a section, update the next section address.
+ if (!F->getNextNode()) {
+ unsigned NextIndex = F->getParent()->getLayoutOrder() + 1;
+ if (NextIndex != getSectionOrder().size())
+ LayoutSection(getSectionOrder()[NextIndex]);
+ }
+}
- // Align the fragment offset; it is safe to adjust the offset freely since
- // this is only in virtual sections.
- //
- // FIXME: We shouldn't be doing this here.
- Address = RoundUpToAlignment(Address, ZFF.getAlignment());
- Layout.setFragmentOffset(&F, Address - StartAddress);
+void MCAsmLayout::LayoutSection(MCSectionData *SD) {
+ unsigned SectionOrderIndex = SD->getLayoutOrder();
- EffectiveSize = ZFF.getSize();
- break;
- }
- }
+ ++stats::SectionLayouts;
- Layout.setFragmentEffectiveSize(&F, EffectiveSize);
- Address += EffectiveSize;
+ // Compute the section start address.
+ uint64_t StartAddress = 0;
+ if (SectionOrderIndex) {
+ MCSectionData *Prev = getSectionOrder()[SectionOrderIndex - 1];
+ StartAddress = getSectionAddress(Prev) + getSectionAddressSize(Prev);
}
- // Set the section sizes.
- Layout.setSectionSize(&SD, Address - StartAddress);
- if (IsVirtual)
- Layout.setSectionFileSize(&SD, 0);
- else
- Layout.setSectionFileSize(&SD, Address - StartAddress);
+ // Honor the section alignment requirements.
+ StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment());
- return Address;
+ // Set the section address.
+ SD->Address = StartAddress;
}
/// WriteFragmentData - Write the \arg F data to the output file.
@@ -522,6 +533,8 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
MCAlignFragment &AF = cast<MCAlignFragment>(F);
uint64_t Count = FragmentSize / AF.getValueSize();
+ assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!");
+
// FIXME: This error shouldn't actually occur (the front end should emit
// multiple .align directives to enforce the semantics it wants), but is
// severe enough that we want to report it. How to handle this?
@@ -535,7 +548,7 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
// the Count bytes. Then if that did not fill any bytes or there are any
// bytes left to fill use the the Value and ValueSize to fill the rest.
// If we are aligning with nops, ask that target to emit the right data.
- if (AF.getEmitNops()) {
+ if (AF.hasEmitNops()) {
if (!Asm.getBackend().WriteNopData(Count, OW))
report_fatal_error("unable to write nop sequence of " +
Twine(Count) + " bytes");
@@ -565,7 +578,10 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
case MCFragment::FT_Fill: {
MCFillFragment &FF = cast<MCFillFragment>(F);
- for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) {
+
+ assert(FF.getValueSize() && "Invalid virtual align in concrete fragment!");
+
+ for (uint64_t i = 0, e = FF.getSize() / FF.getValueSize(); i != e; ++i) {
switch (FF.getValueSize()) {
default:
assert(0 && "Invalid size!");
@@ -590,11 +606,6 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
break;
}
-
- case MCFragment::FT_ZeroFill: {
- assert(0 && "Invalid zero fill fragment in concrete section!");
- break;
- }
}
assert(OW->getStream().tell() - Start == FragmentSize);
@@ -603,12 +614,27 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
void MCAssembler::WriteSectionData(const MCSectionData *SD,
const MCAsmLayout &Layout,
MCObjectWriter *OW) const {
- uint64_t SectionSize = Layout.getSectionSize(SD);
- uint64_t SectionFileSize = Layout.getSectionFileSize(SD);
-
// Ignore virtual sections.
if (getBackend().isVirtualSection(SD->getSection())) {
- assert(SectionFileSize == 0 && "Invalid size for section!");
+ assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!");
+
+ // Check that contents are only things legal inside a virtual section.
+ for (MCSectionData::const_iterator it = SD->begin(),
+ ie = SD->end(); it != ie; ++it) {
+ switch (it->getKind()) {
+ default:
+ assert(0 && "Invalid fragment in virtual section!");
+ case MCFragment::FT_Align:
+ assert(!cast<MCAlignFragment>(it)->getValueSize() &&
+ "Invalid align in virtual section!");
+ break;
+ case MCFragment::FT_Fill:
+ assert(!cast<MCFillFragment>(it)->getValueSize() &&
+ "Invalid fill in virtual section!");
+ break;
+ }
+ }
+
return;
}
@@ -619,11 +645,7 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD,
ie = SD->end(); it != ie; ++it)
WriteFragmentData(*this, Layout, *it, OW);
- // Add section padding.
- assert(SectionFileSize >= SectionSize && "Invalid section sizes!");
- OW->WriteZeros(SectionFileSize - SectionSize);
-
- assert(OW->getStream().tell() - Start == SectionFileSize);
+ assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD));
}
void MCAssembler::Finish() {
@@ -631,20 +653,60 @@ void MCAssembler::Finish() {
llvm::errs() << "assembler backend - pre-layout\n--\n";
dump(); });
- // Assign section and fragment ordinals, all subsequent backend code is
- // responsible for updating these in place.
+ // Create the layout object.
+ MCAsmLayout Layout(*this);
+
+ // Insert additional align fragments for concrete sections to explicitly pad
+ // the previous section to match their alignment requirements. This is for
+ // 'gas' compatibility, it shouldn't strictly be necessary.
+ //
+ // FIXME: This may be Mach-O specific.
+ for (unsigned i = 1, e = Layout.getSectionOrder().size(); i < e; ++i) {
+ MCSectionData *SD = Layout.getSectionOrder()[i];
+
+ // Ignore sections without alignment requirements.
+ unsigned Align = SD->getAlignment();
+ if (Align <= 1)
+ continue;
+
+ // Ignore virtual sections, they don't cause file size modifications.
+ if (getBackend().isVirtualSection(SD->getSection()))
+ continue;
+
+ // Otherwise, create a new align fragment at the end of the previous
+ // section.
+ MCAlignFragment *AF = new MCAlignFragment(Align, 0, 1, Align,
+ Layout.getSectionOrder()[i - 1]);
+ AF->setOnlyAlignAddress(true);
+ }
+
+ // Create dummy fragments and assign section ordinals.
unsigned SectionIndex = 0;
- unsigned FragmentIndex = 0;
for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) {
+ // Create dummy fragments to eliminate any empty sections, this simplifies
+ // layout.
+ if (it->getFragmentList().empty()) {
+ unsigned ValueSize = 1;
+ if (getBackend().isVirtualSection(it->getSection()))
+ ValueSize = 1;
+ new MCFillFragment(0, 1, 0, it);
+ }
+
it->setOrdinal(SectionIndex++);
+ }
- for (MCSectionData::iterator it2 = it->begin(),
- ie2 = it->end(); it2 != ie2; ++it2)
- it2->setOrdinal(FragmentIndex++);
+ // Assign layout order indices to sections and fragments.
+ unsigned FragmentIndex = 0;
+ for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) {
+ MCSectionData *SD = Layout.getSectionOrder()[i];
+ SD->setLayoutOrder(i);
+
+ for (MCSectionData::iterator it2 = SD->begin(),
+ ie2 = SD->end(); it2 != ie2; ++it2)
+ it2->setLayoutOrder(FragmentIndex++);
}
// Layout until everything fits.
- MCAsmLayout Layout(*this);
while (LayoutOnce(Layout))
continue;
@@ -678,7 +740,7 @@ void MCAssembler::Finish() {
for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(),
ie3 = DF->fixup_end(); it3 != ie3; ++it3) {
- MCAsmFixup &Fixup = *it3;
+ MCFixup &Fixup = *it3;
// Evaluate the fixup.
MCValue Target;
@@ -702,7 +764,7 @@ void MCAssembler::Finish() {
stats::ObjectBytes += OS.tell() - StartOffset;
}
-bool MCAssembler::FixupNeedsRelaxation(const MCAsmFixup &Fixup,
+bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup,
const MCFragment *DF,
const MCAsmLayout &Layout) const {
if (getRelaxAll())
@@ -725,7 +787,7 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF,
// If this inst doesn't ever need relaxation, ignore it. This occurs when we
// are intentionally pushing out inst fragments, or because we relaxed a
// previous instruction to one that doesn't need relaxation.
- if (!getBackend().MayNeedRelaxation(IF->getInst(), IF->getFixups()))
+ if (!getBackend().MayNeedRelaxation(IF->getInst()))
return false;
for (MCInstFragment::const_fixup_iterator it = IF->fixup_begin(),
@@ -739,25 +801,8 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF,
bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) {
++stats::RelaxationSteps;
- // Layout the concrete sections and fragments.
- uint64_t Address = 0;
- for (iterator it = begin(), ie = end(); it != ie; ++it) {
- // Skip virtual sections.
- if (getBackend().isVirtualSection(it->getSection()))
- continue;
-
- // Layout the section fragments and its size.
- Address = LayoutSection(*it, Layout, Address);
- }
-
- // Layout the virtual sections.
- for (iterator it = begin(), ie = end(); it != ie; ++it) {
- if (!getBackend().isVirtualSection(it->getSection()))
- continue;
-
- // Layout the section fragments and its size.
- Address = LayoutSection(*it, Layout, Address);
- }
+ // Layout the sections in order.
+ Layout.LayoutFile();
// Scan for fragments that need relaxation.
bool WasRelaxed = false;
@@ -779,7 +824,7 @@ bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) {
// Relax the fragment.
MCInst Relaxed;
- getBackend().RelaxInstruction(IF, Relaxed);
+ getBackend().RelaxInstruction(IF->getInst(), Relaxed);
// Encode the new instruction.
//
@@ -796,17 +841,12 @@ bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) {
IF->setInst(Relaxed);
IF->getCode() = Code;
IF->getFixups().clear();
- for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
- MCFixup &F = Fixups[i];
- IF->getFixups().push_back(MCAsmFixup(F.getOffset(), *F.getValue(),
- F.getKind()));
- }
+ // FIXME: Eliminate copy.
+ for (unsigned i = 0, e = Fixups.size(); i != e; ++i)
+ IF->getFixups().push_back(Fixups[i]);
- // Update the layout, and remember that we relaxed. If we are relaxing
- // everything, we can skip this step since nothing will depend on updating
- // the values.
- if (!getRelaxAll())
- Layout.UpdateForSlide(IF, SlideAmount);
+ // Update the layout, and remember that we relaxed.
+ Layout.UpdateForSlide(IF, SlideAmount);
WasRelaxed = true;
}
}
@@ -838,12 +878,10 @@ void MCAssembler::FinishLayout(MCAsmLayout &Layout) {
SD.getFragmentList().insert(it2, DF);
// Update the data fragments layout data.
- //
- // FIXME: Add MCAsmLayout utility for this.
DF->setParent(IF->getParent());
- DF->setOrdinal(IF->getOrdinal());
- Layout.setFragmentOffset(DF, Layout.getFragmentOffset(IF));
- Layout.setFragmentEffectiveSize(DF, Layout.getFragmentEffectiveSize(IF));
+ DF->setAtom(IF->getAtom());
+ DF->setLayoutOrder(IF->getLayoutOrder());
+ Layout.FragmentReplaced(IF, DF);
// Copy in the data and the fixups.
DF->getContents().append(IF->getCode().begin(), IF->getCode().end());
@@ -861,9 +899,10 @@ void MCAssembler::FinishLayout(MCAsmLayout &Layout) {
namespace llvm {
-raw_ostream &operator<<(raw_ostream &OS, const MCAsmFixup &AF) {
- OS << "<MCAsmFixup" << " Offset:" << AF.Offset << " Value:" << *AF.Value
- << " Kind:" << AF.Kind << ">";
+raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) {
+ OS << "<MCFixup" << " Offset:" << AF.getOffset()
+ << " Value:" << *AF.getValue()
+ << " Kind:" << AF.getKind() << ">";
return OS;
}
@@ -872,94 +911,82 @@ raw_ostream &operator<<(raw_ostream &OS, const MCAsmFixup &AF) {
void MCFragment::dump() {
raw_ostream &OS = llvm::errs();
- OS << "<MCFragment " << (void*) this << " Offset:" << Offset
- << " EffectiveSize:" << EffectiveSize;
-
- OS << ">";
-}
-
-void MCAlignFragment::dump() {
- raw_ostream &OS = llvm::errs();
+ OS << "<";
+ switch (getKind()) {
+ case MCFragment::FT_Align: OS << "MCAlignFragment"; break;
+ case MCFragment::FT_Data: OS << "MCDataFragment"; break;
+ case MCFragment::FT_Fill: OS << "MCFillFragment"; break;
+ case MCFragment::FT_Inst: OS << "MCInstFragment"; break;
+ case MCFragment::FT_Org: OS << "MCOrgFragment"; break;
+ }
- OS << "<MCAlignFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Alignment:" << getAlignment()
- << " Value:" << getValue() << " ValueSize:" << getValueSize()
- << " MaxBytesToEmit:" << getMaxBytesToEmit() << ">";
-}
+ OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder
+ << " Offset:" << Offset << " EffectiveSize:" << EffectiveSize << ">";
-void MCDataFragment::dump() {
- raw_ostream &OS = llvm::errs();
-
- OS << "<MCDataFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Contents:[";
- for (unsigned i = 0, e = getContents().size(); i != e; ++i) {
- if (i) OS << ",";
- OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
- }
- OS << "] (" << getContents().size() << " bytes)";
-
- if (!getFixups().empty()) {
- OS << ",\n ";
- OS << " Fixups:[";
- for (fixup_iterator it = fixup_begin(), ie = fixup_end(); it != ie; ++it) {
- if (it != fixup_begin()) OS << ",\n ";
- OS << *it;
+ switch (getKind()) {
+ case MCFragment::FT_Align: {
+ const MCAlignFragment *AF = cast<MCAlignFragment>(this);
+ if (AF->hasEmitNops())
+ OS << " (emit nops)";
+ if (AF->hasOnlyAlignAddress())
+ OS << " (only align section)";
+ OS << "\n ";
+ OS << " Alignment:" << AF->getAlignment()
+ << " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize()
+ << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">";
+ break;
+ }
+ case MCFragment::FT_Data: {
+ const MCDataFragment *DF = cast<MCDataFragment>(this);
+ OS << "\n ";
+ OS << " Contents:[";
+ const SmallVectorImpl<char> &Contents = DF->getContents();
+ for (unsigned i = 0, e = Contents.size(); i != e; ++i) {
+ if (i) OS << ",";
+ OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
}
- OS << "]";
+ OS << "] (" << Contents.size() << " bytes)";
+
+ if (!DF->getFixups().empty()) {
+ OS << ",\n ";
+ OS << " Fixups:[";
+ for (MCDataFragment::const_fixup_iterator it = DF->fixup_begin(),
+ ie = DF->fixup_end(); it != ie; ++it) {
+ if (it != DF->fixup_begin()) OS << ",\n ";
+ OS << *it;
+ }
+ OS << "]";
+ }
+ break;
+ }
+ case MCFragment::FT_Fill: {
+ const MCFillFragment *FF = cast<MCFillFragment>(this);
+ OS << " Value:" << FF->getValue() << " ValueSize:" << FF->getValueSize()
+ << " Size:" << FF->getSize();
+ break;
+ }
+ case MCFragment::FT_Inst: {
+ const MCInstFragment *IF = cast<MCInstFragment>(this);
+ OS << "\n ";
+ OS << " Inst:";
+ IF->getInst().dump_pretty(OS);
+ break;
+ }
+ case MCFragment::FT_Org: {
+ const MCOrgFragment *OF = cast<MCOrgFragment>(this);
+ OS << "\n ";
+ OS << " Offset:" << OF->getOffset() << " Value:" << OF->getValue();
+ break;
+ }
}
-
- OS << ">";
-}
-
-void MCFillFragment::dump() {
- raw_ostream &OS = llvm::errs();
-
- OS << "<MCFillFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Value:" << getValue() << " ValueSize:" << getValueSize()
- << " Count:" << getCount() << ">";
-}
-
-void MCInstFragment::dump() {
- raw_ostream &OS = llvm::errs();
-
- OS << "<MCInstFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Inst:";
- getInst().dump_pretty(OS);
OS << ">";
}
-void MCOrgFragment::dump() {
- raw_ostream &OS = llvm::errs();
-
- OS << "<MCOrgFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Offset:" << getOffset() << " Value:" << getValue() << ">";
-}
-
-void MCZeroFillFragment::dump() {
- raw_ostream &OS = llvm::errs();
-
- OS << "<MCZeroFillFragment ";
- this->MCFragment::dump();
- OS << "\n ";
- OS << " Size:" << getSize() << " Alignment:" << getAlignment() << ">";
-}
-
void MCSectionData::dump() {
raw_ostream &OS = llvm::errs();
OS << "<MCSectionData";
OS << " Alignment:" << getAlignment() << " Address:" << Address
- << " Size:" << Size << " FileSize:" << FileSize
<< " Fragments:[\n ";
for (iterator it = begin(), ie = end(); it != ie; ++it) {
if (it != begin()) OS << ",\n ";
diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp
index dc757bb..53ffc94 100644
--- a/lib/MC/MCContext.cpp
+++ b/lib/MC/MCContext.cpp
@@ -11,18 +11,22 @@
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionCOFF.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCLabel.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
using namespace llvm;
typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy;
typedef StringMap<const MCSectionELF*> ELFUniqueMapTy;
+typedef StringMap<const MCSectionCOFF*> COFFUniqueMapTy;
MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) {
MachOUniquingMap = 0;
ELFUniquingMap = 0;
+ COFFUniquingMap = 0;
}
MCContext::~MCContext() {
@@ -32,6 +36,7 @@ MCContext::~MCContext() {
// If we have the MachO uniquing map, free it.
delete (MachOUniqueMapTy*)MachOUniquingMap;
delete (ELFUniqueMapTy*)ELFUniquingMap;
+ delete (COFFUniqueMapTy*)COFFUniquingMap;
}
//===----------------------------------------------------------------------===//
@@ -67,6 +72,34 @@ MCSymbol *MCContext::CreateTempSymbol() {
"tmp" + Twine(NextUniqueID++));
}
+unsigned MCContext::NextInstance(int64_t LocalLabelVal) {
+ MCLabel *&Label = Instances[LocalLabelVal];
+ if (!Label)
+ Label = new (*this) MCLabel(0);
+ return Label->incInstance();
+}
+
+unsigned MCContext::GetInstance(int64_t LocalLabelVal) {
+ MCLabel *&Label = Instances[LocalLabelVal];
+ if (!Label)
+ Label = new (*this) MCLabel(0);
+ return Label->getInstance();
+}
+
+MCSymbol *MCContext::CreateDirectionalLocalSymbol(int64_t LocalLabelVal) {
+ return GetOrCreateSymbol(Twine(MAI.getPrivateGlobalPrefix()) +
+ Twine(LocalLabelVal) +
+ "\2" +
+ Twine(NextInstance(LocalLabelVal)));
+}
+MCSymbol *MCContext::GetDirectionalLocalSymbol(int64_t LocalLabelVal,
+ int bORf) {
+ return GetOrCreateSymbol(Twine(MAI.getPrivateGlobalPrefix()) +
+ Twine(LocalLabelVal) +
+ "\2" +
+ Twine(GetInstance(LocalLabelVal) + bORf));
+}
+
MCSymbol *MCContext::LookupSymbol(StringRef Name) const {
return Symbols.lookup(Name);
}
@@ -122,4 +155,22 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags,
return Result;
}
-
+const MCSection *MCContext::getCOFFSection(StringRef Section,
+ unsigned Characteristics,
+ int Selection,
+ SectionKind Kind) {
+ if (COFFUniquingMap == 0)
+ COFFUniquingMap = new COFFUniqueMapTy();
+ COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap;
+
+ // Do the lookup, if we have a hit, return it.
+ StringMapEntry<const MCSectionCOFF*> &Entry = Map.GetOrCreateValue(Section);
+ if (Entry.getValue()) return Entry.getValue();
+
+ MCSectionCOFF *Result = new (*this) MCSectionCOFF(Entry.getKey(),
+ Characteristics,
+ Selection, Kind);
+
+ Entry.setValue(Result);
+ return Result;
+}
diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp
index bc670ab..c000dd7 100644
--- a/lib/MC/MCExpr.cpp
+++ b/lib/MC/MCExpr.cpp
@@ -39,6 +39,10 @@ void MCExpr::print(raw_ostream &OS) const {
const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this);
const MCSymbol &Sym = SRE.getSymbol();
+ if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_HI16 ||
+ SRE.getKind() == MCSymbolRefExpr::VK_ARM_LO16)
+ OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind());
+
// Parenthesize names that start with $ so that they don't look like
// absolute names.
if (Sym.getName()[0] == '$')
@@ -46,7 +50,9 @@ void MCExpr::print(raw_ostream &OS) const {
else
OS << Sym;
- if (SRE.getKind() != MCSymbolRefExpr::VK_None)
+ if (SRE.getKind() != MCSymbolRefExpr::VK_None &&
+ SRE.getKind() != MCSymbolRefExpr::VK_ARM_HI16 &&
+ SRE.getKind() != MCSymbolRefExpr::VK_ARM_LO16)
OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind());
return;
@@ -169,6 +175,9 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_PLT: return "PLT";
case VK_TLSGD: return "TLSGD";
case VK_TPOFF: return "TPOFF";
+ case VK_ARM_HI16: return ":upper16:";
+ case VK_ARM_LO16: return ":lower16:";
+ case VK_TLVP: return "TLVP";
}
}
@@ -184,6 +193,7 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("PLT", VK_PLT)
.Case("TLSGD", VK_TLSGD)
.Case("TPOFF", VK_TPOFF)
+ .Case("TLVP", VK_TLVP)
.Default(VK_Invalid);
}
@@ -249,7 +259,7 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res,
// Evaluate recursively if this is a variable.
if (Sym.isVariable()) {
- if (!Sym.getValue()->EvaluateAsRelocatable(Res, Layout))
+ if (!Sym.getVariableValue()->EvaluateAsRelocatable(Res, Layout))
return false;
// Absolutize symbol differences between defined symbols when we have a
diff --git a/lib/MC/MCInst.cpp b/lib/MC/MCInst.cpp
index de142dc..4cb628b 100644
--- a/lib/MC/MCInst.cpp
+++ b/lib/MC/MCInst.cpp
@@ -57,7 +57,7 @@ void MCInst::dump_pretty(raw_ostream &OS, const MCAsmInfo *MAI,
OS << Separator;
getOperand(i).print(OS, MAI);
}
- OS << ">\n";
+ OS << ">";
}
void MCInst::dump() const {
diff --git a/lib/MC/MCLabel.cpp b/lib/MC/MCLabel.cpp
new file mode 100644
index 0000000..9c0fc92
--- /dev/null
+++ b/lib/MC/MCLabel.cpp
@@ -0,0 +1,21 @@
+//===- lib/MC/MCLabel.cpp - MCLabel implementation ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCLabel.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+void MCLabel::print(raw_ostream &OS) const {
+ OS << '"' << getInstance() << '"';
+}
+
+void MCLabel::dump() const {
+ print(dbgs());
+}
diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp
new file mode 100644
index 0000000..b96040a
--- /dev/null
+++ b/lib/MC/MCLoggingStreamer.cpp
@@ -0,0 +1,208 @@
+//===- lib/MC/MCLoggingStreamer.cpp - API Logging Streamer ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+namespace {
+
+class MCLoggingStreamer : public MCStreamer {
+ llvm::OwningPtr<MCStreamer> Child;
+
+ raw_ostream &OS;
+
+public:
+ MCLoggingStreamer(MCStreamer *_Child, raw_ostream &_OS)
+ : MCStreamer(_Child->getContext()), Child(_Child), OS(_OS) {}
+
+ void LogCall(const char *Function) {
+ OS << Function << "\n";
+ }
+
+ void LogCall(const char *Function, const Twine &Message) {
+ OS << Function << ": " << Message << "\n";
+ }
+
+ virtual bool isVerboseAsm() const { return Child->isVerboseAsm(); }
+
+ virtual bool hasRawTextSupport() const { return Child->hasRawTextSupport(); }
+
+ virtual raw_ostream &GetCommentOS() { return Child->GetCommentOS(); }
+
+ virtual void AddComment(const Twine &T) {
+ LogCall("AddComment", T);
+ return Child->AddComment(T);
+ }
+
+ virtual void AddBlankLine() {
+ LogCall("AddBlankLine");
+ return Child->AddBlankLine();
+ }
+
+ virtual void SwitchSection(const MCSection *Section) {
+ CurSection = Section;
+ LogCall("SwitchSection");
+ return Child->SwitchSection(Section);
+ }
+
+ virtual void EmitLabel(MCSymbol *Symbol) {
+ LogCall("EmitLabel");
+ return Child->EmitLabel(Symbol);
+ }
+
+ virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {
+ LogCall("EmitAssemblerFlag");
+ return Child->EmitAssemblerFlag(Flag);
+ }
+
+ virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ LogCall("EmitAssignment");
+ return Child->EmitAssignment(Symbol, Value);
+ }
+
+ virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) {
+ LogCall("EmitSymbolAttribute");
+ return Child->EmitSymbolAttribute(Symbol, Attribute);
+ }
+
+ virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+ LogCall("EmitSymbolDesc");
+ return Child->EmitSymbolDesc(Symbol, DescValue);
+ }
+
+ virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {
+ LogCall("BeginCOFFSymbolDef");
+ return Child->BeginCOFFSymbolDef(Symbol);
+ }
+
+ virtual void EmitCOFFSymbolStorageClass(int StorageClass) {
+ LogCall("EmitCOFFSymbolStorageClass");
+ return Child->EmitCOFFSymbolStorageClass(StorageClass);
+ }
+
+ virtual void EmitCOFFSymbolType(int Type) {
+ LogCall("EmitCOFFSymbolType");
+ return Child->EmitCOFFSymbolType(Type);
+ }
+
+ virtual void EndCOFFSymbolDef() {
+ LogCall("EndCOFFSymbolDef");
+ return Child->EndCOFFSymbolDef();
+ }
+
+ virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
+ LogCall("EmitELFSize");
+ return Child->EmitELFSize(Symbol, Value);
+ }
+
+ virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ LogCall("EmitCommonSymbol");
+ return Child->EmitCommonSymbol(Symbol, Size, ByteAlignment);
+ }
+
+ virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) {
+ LogCall("EmitLocalCommonSymbol");
+ return Child->EmitLocalCommonSymbol(Symbol, Size);
+ }
+
+ virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
+ unsigned Size = 0, unsigned ByteAlignment = 0) {
+ LogCall("EmitZerofill");
+ return Child->EmitZerofill(Section, Symbol, Size, ByteAlignment);
+ }
+
+ virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment = 0) {
+ LogCall("EmitTBSSSymbol");
+ return Child->EmitTBSSSymbol(Section, Symbol, Size, ByteAlignment);
+ }
+
+ virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {
+ LogCall("EmitBytes");
+ return Child->EmitBytes(Data, AddrSpace);
+ }
+
+ virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace){
+ LogCall("EmitValue");
+ return Child->EmitValue(Value, Size, AddrSpace);
+ }
+
+ virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) {
+ LogCall("EmitIntValue");
+ return Child->EmitIntValue(Value, Size, AddrSpace);
+ }
+
+ virtual void EmitGPRel32Value(const MCExpr *Value) {
+ LogCall("EmitGPRel32Value");
+ return Child->EmitGPRel32Value(Value);
+ }
+
+ virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue,
+ unsigned AddrSpace) {
+ LogCall("EmitFill");
+ return Child->EmitFill(NumBytes, FillValue, AddrSpace);
+ }
+
+ virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
+ unsigned ValueSize = 1,
+ unsigned MaxBytesToEmit = 0) {
+ LogCall("EmitValueToAlignment");
+ return Child->EmitValueToAlignment(ByteAlignment, Value,
+ ValueSize, MaxBytesToEmit);
+ }
+
+ virtual void EmitCodeAlignment(unsigned ByteAlignment,
+ unsigned MaxBytesToEmit = 0) {
+ LogCall("EmitCodeAlignment");
+ return Child->EmitCodeAlignment(ByteAlignment, MaxBytesToEmit);
+ }
+
+ virtual void EmitValueToOffset(const MCExpr *Offset,
+ unsigned char Value = 0) {
+ LogCall("EmitValueToOffset");
+ return Child->EmitValueToOffset(Offset, Value);
+ }
+
+ virtual void EmitFileDirective(StringRef Filename) {
+ LogCall("EmitFileDirective", "FileName:" + Filename);
+ return Child->EmitFileDirective(Filename);
+ }
+
+ virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
+ LogCall("EmitDwarfFileDirective",
+ "FileNo:" + Twine(FileNo) + " Filename:" + Filename);
+ return Child->EmitDwarfFileDirective(FileNo, Filename);
+ }
+
+ virtual void EmitInstruction(const MCInst &Inst) {
+ LogCall("EmitInstruction");
+ return Child->EmitInstruction(Inst);
+ }
+
+ virtual void EmitRawText(StringRef String) {
+ LogCall("EmitRawText", "\"" + String + "\"");
+ return Child->EmitRawText(String);
+ }
+
+ virtual void Finish() {
+ LogCall("Finish");
+ return Child->Finish();
+ }
+
+};
+
+} // end anonymous namespace.
+
+MCStreamer *llvm::createLoggingStreamer(MCStreamer *Child, raw_ostream &OS) {
+ return new MCLoggingStreamer(Child, OS);
+}
diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp
index 120f837..27e4e98 100644
--- a/lib/MC/MCMachOStreamer.cpp
+++ b/lib/MC/MCMachOStreamer.cpp
@@ -16,6 +16,7 @@
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCMachOSymbolFlags.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetAsmBackend.h"
@@ -25,30 +26,14 @@ using namespace llvm;
namespace {
class MCMachOStreamer : public MCStreamer {
- /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest
- /// 16 bits of the implementation defined flags.
- enum SymbolFlags { // See <mach-o/nlist.h>.
- SF_DescFlagsMask = 0xFFFF,
-
- // Reference type flags.
- SF_ReferenceTypeMask = 0x0007,
- SF_ReferenceTypeUndefinedNonLazy = 0x0000,
- SF_ReferenceTypeUndefinedLazy = 0x0001,
- SF_ReferenceTypeDefined = 0x0002,
- SF_ReferenceTypePrivateDefined = 0x0003,
- SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004,
- SF_ReferenceTypePrivateUndefinedLazy = 0x0005,
-
- // Other 'desc' flags.
- SF_NoDeadStrip = 0x0020,
- SF_WeakReference = 0x0040,
- SF_WeakDefinition = 0x0080
- };
private:
MCAssembler Assembler;
MCSectionData *CurSectionData;
+ /// Track the current atom for each section.
+ DenseMap<const MCSectionData*, MCSymbolData*> CurrentAtomMap;
+
private:
MCFragment *getCurrentFragment() const {
assert(CurSectionData && "No current section!");
@@ -64,10 +49,20 @@ private:
MCDataFragment *getOrCreateDataFragment() const {
MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
if (!F)
- F = new MCDataFragment(CurSectionData);
+ F = createDataFragment();
return F;
}
+ /// Create a new data fragment in the current section.
+ MCDataFragment *createDataFragment() const {
+ MCDataFragment *DF = new MCDataFragment(CurSectionData);
+ DF->setAtom(CurrentAtomMap.lookup(CurSectionData));
+ return DF;
+ }
+
+ void EmitInstToFragment(const MCInst &Inst);
+ void EmitInstToData(const MCInst &Inst);
+
public:
MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB,
raw_ostream &_OS, MCCodeEmitter *_Emitter)
@@ -114,6 +109,18 @@ public:
virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue);
virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment);
+ virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {
+ assert(0 && "macho doesn't support this directive");
+ }
+ virtual void EmitCOFFSymbolStorageClass(int StorageClass) {
+ assert(0 && "macho doesn't support this directive");
+ }
+ virtual void EmitCOFFSymbolType(int Type) {
+ assert(0 && "macho doesn't support this directive");
+ }
+ virtual void EndCOFFSymbolDef() {
+ assert(0 && "macho doesn't support this directive");
+ }
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
assert(0 && "macho doesn't support this directive");
}
@@ -122,6 +129,8 @@ public:
}
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 0);
+ virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment = 0);
virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace);
virtual void EmitGPRel32Value(const MCExpr *Value) {
@@ -134,14 +143,14 @@ public:
unsigned MaxBytesToEmit = 0);
virtual void EmitValueToOffset(const MCExpr *Offset,
unsigned char Value = 0);
-
+
virtual void EmitFileDirective(StringRef Filename) {
- errs() << "FIXME: MCMachoStreamer:EmitFileDirective not implemented\n";
+ report_fatal_error("unsupported directive: '.file'");
}
virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
- errs() << "FIXME: MCMachoStreamer:EmitDwarfFileDirective not implemented\n";
+ report_fatal_error("unsupported directive: '.file'");
}
-
+
virtual void EmitInstruction(const MCInst &Inst);
virtual void Finish();
@@ -152,7 +161,7 @@ public:
void MCMachOStreamer::SwitchSection(const MCSection *Section) {
assert(Section && "Cannot switch to a null section!");
-
+
// If already in this section, then this is a noop.
if (Section == CurSection) return;
@@ -162,20 +171,39 @@ void MCMachOStreamer::SwitchSection(const MCSection *Section) {
void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
+ assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
+ assert(CurSection && "Cannot emit before setting section!");
+
+ MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
+
+ // Update the current atom map, if necessary.
+ bool MustCreateFragment = false;
+ if (Assembler.isSymbolLinkerVisible(&SD)) {
+ CurrentAtomMap[CurSectionData] = &SD;
+
+ // We have to create a new fragment, fragments cannot span atoms.
+ MustCreateFragment = true;
+ }
// 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 = Assembler.getOrCreateSymbolData(*Symbol);
+ MCDataFragment *F =
+ MustCreateFragment ? createDataFragment() : getOrCreateDataFragment();
assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
SD.setFragment(F);
SD.setOffset(F->getContents().size());
- // This causes the reference type and weak reference flags to be cleared.
- SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask));
-
+ // This causes the reference type flag to be cleared. Darwin 'as' was "trying"
+ // to clear the weak reference and weak definition bits too, but the
+ // implementation was buggy. For now we just try to match 'as', for
+ // diffability.
+ //
+ // FIXME: Cleanup this code, these bits should be emitted based on semantic
+ // properties, not on the order of definition, etc.
+ SD.setFlags(SD.getFlags() & ~SF_ReferenceTypeMask);
+
Symbol->setSection(*CurSection);
}
@@ -190,13 +218,9 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
}
void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
- // Only absolute symbols can be redefined.
- assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
- "Cannot define a symbol twice!");
-
// FIXME: Lift context changes into super class.
- // FIXME: Set associated section.
- Symbol->setValue(AddValueSymbols(Value));
+ Assembler.getOrCreateSymbolData(*Symbol);
+ Symbol->setVariableValue(AddValueSymbols(Value));
}
void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
@@ -243,6 +267,13 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
case MCSA_Global:
SD.setExternal(true);
+ // This effectively clears the undefined lazy bit, in Darwin 'as', although
+ // it isn't very consistent because it implements this as part of symbol
+ // lookup.
+ //
+ // FIXME: Cleanup this code, these bits should be emitted based on semantic
+ // properties, not on the order of definition, etc.
+ SD.setFlags(SD.getFlags() & ~SF_ReferenceTypeUndefinedLazy);
break;
case MCSA_LazyReference:
@@ -280,7 +311,7 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
// Encode the 'desc' value into the lowest implementation defined bits.
- assert(DescValue == (DescValue & SF_DescFlagsMask) &&
+ assert(DescValue == (DescValue & SF_DescFlagsMask) &&
"Invalid .desc value!");
Assembler.getOrCreateSymbolData(*Symbol).setFlags(DescValue&SF_DescFlagsMask);
}
@@ -309,8 +340,14 @@ void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
- MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData);
+ // Emit an align fragment if necessary.
+ if (ByteAlignment != 1)
+ new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectData);
+
+ MCFragment *F = new MCFillFragment(0, 0, Size, &SectData);
SD.setFragment(F);
+ if (Assembler.isSymbolLinkerVisible(&SD))
+ F->setAtom(&SD);
Symbol->setSection(*Section);
@@ -319,6 +356,14 @@ void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
SectData.setAlignment(ByteAlignment);
}
+// This should always be called with the thread local bss section. Like the
+// .zerofill directive this doesn't actually switch sections on us.
+void MCMachOStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ EmitZerofill(Section, Symbol, Size, ByteAlignment);
+ return;
+}
+
void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end());
}
@@ -334,8 +379,9 @@ void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size,
for (unsigned i = 0; i != Size; ++i)
DF->getContents().push_back(uint8_t(AbsValue >> (i * 8)));
} else {
- DF->addFixup(MCAsmFixup(DF->getContents().size(), *AddValueSymbols(Value),
- MCFixup::getKindForSize(Size)));
+ DF->addFixup(MCFixup::Create(DF->getContents().size(),
+ AddValueSymbols(Value),
+ MCFixup::getKindForSize(Size)));
DF->getContents().resize(DF->getContents().size() + Size, 0);
}
}
@@ -345,8 +391,9 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment,
unsigned MaxBytesToEmit) {
if (MaxBytesToEmit == 0)
MaxBytesToEmit = ByteAlignment;
- new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
- false /* EmitNops */, CurSectionData);
+ MCFragment *F = new MCAlignFragment(ByteAlignment, Value, ValueSize,
+ MaxBytesToEmit, CurSectionData);
+ F->setAtom(CurrentAtomMap.lookup(CurSectionData));
// Update the maximum alignment on the current section if necessary.
if (ByteAlignment > CurSectionData->getAlignment())
@@ -357,8 +404,10 @@ void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment,
unsigned MaxBytesToEmit) {
if (MaxBytesToEmit == 0)
MaxBytesToEmit = ByteAlignment;
- new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit,
- true /* EmitNops */, CurSectionData);
+ MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit,
+ CurSectionData);
+ F->setEmitNops(true);
+ F->setAtom(CurrentAtomMap.lookup(CurSectionData));
// Update the maximum alignment on the current section if necessary.
if (ByteAlignment > CurSectionData->getAlignment())
@@ -367,19 +416,30 @@ void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment,
void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset,
unsigned char Value) {
- new MCOrgFragment(*Offset, Value, CurSectionData);
+ MCFragment *F = new MCOrgFragment(*Offset, Value, CurSectionData);
+ F->setAtom(CurrentAtomMap.lookup(CurSectionData));
}
-void MCMachOStreamer::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 MCMachOStreamer::EmitInstToFragment(const MCInst &Inst) {
+ MCInstFragment *IF = new MCInstFragment(Inst, CurSectionData);
+ IF->setAtom(CurrentAtomMap.lookup(CurSectionData));
- CurSectionData->setHasInstructions(true);
+ // 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);
+ Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
+ VecOS.flush();
- // FIXME-PERF: Common case is that we don't need to relax, encode directly
- // onto the data fragments buffers.
+ IF->getCode() = Code;
+ IF->getFixups() = Fixups;
+}
+
+void MCMachOStreamer::EmitInstToData(const MCInst &Inst) {
+ MCDataFragment *DF = getOrCreateDataFragment();
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
@@ -387,47 +447,41 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups);
VecOS.flush();
- // FIXME: Eliminate this copy.
- SmallVector<MCAsmFixup, 4> AsmFixups;
+ // Add the fixups and data.
for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
- MCFixup &F = Fixups[i];
- AsmFixups.push_back(MCAsmFixup(F.getOffset(), *F.getValue(),
- F.getKind()));
+ Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
+ DF->addFixup(Fixups[i]);
}
+ DF->getContents().append(Code.begin(), Code.end());
+}
- // See if we might need to relax this instruction, if so it needs its own
- // fragment.
- //
- // FIXME-PERF: Support target hook to do a fast path that avoids the encoder,
- // when we can immediately tell that we will get something which might need
- // relaxation (and compute its size).
- //
- // FIXME-PERF: We should also be smart about immediately relaxing instructions
- // which we can already show will never possibly fit (we can also do a very
- // good job of this before we do the first relaxation pass, because we have
- // total knowledge about undefined symbols at that point). Even now, though,
- // we can do a decent job, especially on Darwin where scattering means that we
- // are going to often know that we can never fully resolve a fixup.
- if (Assembler.getBackend().MayNeedRelaxation(Inst, AsmFixups)) {
- MCInstFragment *IF = new MCInstFragment(Inst, CurSectionData);
-
- // 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.
- IF->getCode() = Code;
- IF->getFixups() = AsmFixups;
+void MCMachOStreamer::EmitInstruction(const MCInst &Inst) {
+ // Scan for values.
+ for (unsigned i = Inst.getNumOperands(); i--; )
+ if (Inst.getOperand(i).isExpr())
+ AddValueSymbols(Inst.getOperand(i).getExpr());
+ CurSectionData->setHasInstructions(true);
+
+ // If this instruction doesn't need relaxation, just emit it as data.
+ if (!Assembler.getBackend().MayNeedRelaxation(Inst)) {
+ EmitInstToData(Inst);
return;
}
- // Add the fixups and data.
- MCDataFragment *DF = getOrCreateDataFragment();
- for (unsigned i = 0, e = AsmFixups.size(); i != e; ++i) {
- AsmFixups[i].Offset += DF->getContents().size();
- DF->addFixup(AsmFixups[i]);
+ // Otherwise, if we are relaxing everything, relax the instruction as much as
+ // possible and emit it as data.
+ if (Assembler.getRelaxAll()) {
+ MCInst Relaxed;
+ Assembler.getBackend().RelaxInstruction(Inst, Relaxed);
+ while (Assembler.getBackend().MayNeedRelaxation(Relaxed))
+ Assembler.getBackend().RelaxInstruction(Relaxed, Relaxed);
+ EmitInstToData(Relaxed);
+ return;
}
- DF->getContents().append(Code.begin(), Code.end());
+
+ // Otherwise emit to a separate fragment.
+ EmitInstToFragment(Inst);
}
void MCMachOStreamer::Finish() {
diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp
index 5f0c64a..5332ade 100644
--- a/lib/MC/MCNullStreamer.cpp
+++ b/lib/MC/MCNullStreamer.cpp
@@ -42,6 +42,12 @@ namespace {
virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){}
virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {}
+
+ virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {}
+ virtual void EmitCOFFSymbolStorageClass(int StorageClass) {}
+ virtual void EmitCOFFSymbolType(int Type) {}
+ virtual void EndCOFFSymbolDef() {}
+
virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {}
virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
unsigned ByteAlignment) {}
@@ -49,7 +55,8 @@ namespace {
virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0,
unsigned Size = 0, unsigned ByteAlignment = 0) {}
-
+ virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {}
virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {}
virtual void EmitValue(const MCExpr *Value, unsigned Size,
diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp
index 1183312..1cbe09a 100644
--- a/lib/MC/MCParser/AsmLexer.cpp
+++ b/lib/MC/MCParser/AsmLexer.cpp
@@ -132,11 +132,6 @@ AsmToken AsmLexer::LexLineComment() {
/// Decimal integer: [1-9][0-9]*
/// TODO: FP literal.
AsmToken AsmLexer::LexDigit() {
- if (*CurPtr == ':')
- return ReturnError(TokStart, "FIXME: local label not implemented");
- if (*CurPtr == 'f' || *CurPtr == 'b')
- return ReturnError(TokStart, "FIXME: directional label not implemented");
-
// Decimal integer: [1-9][0-9]*
if (CurPtr[-1] != '0') {
while (isdigit(*CurPtr))
@@ -158,6 +153,12 @@ AsmToken AsmLexer::LexDigit() {
if (*CurPtr == 'b') {
++CurPtr;
+ // See if we actually have "0b" as part of something like "jmp 0b\n"
+ if (!isdigit(CurPtr[0])) {
+ --CurPtr;
+ StringRef Result(TokStart, CurPtr - TokStart);
+ return AsmToken(AsmToken::Integer, Result, 0);
+ }
const char *NumStart = CurPtr;
while (CurPtr[0] == '0' || CurPtr[0] == '1')
++CurPtr;
@@ -280,6 +281,7 @@ AsmToken AsmLexer::LexToken() {
case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1));
case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1));
case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1));
+ case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1));
case '=':
if (*CurPtr == '=')
return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp
index a63d2e4..4523eab 100644
--- a/lib/MC/MCParser/AsmParser.cpp
+++ b/lib/MC/MCParser/AsmParser.cpp
@@ -13,6 +13,7 @@
#include "llvm/MC/MCParser/AsmParser.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
@@ -189,6 +190,9 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
std::pair<StringRef, StringRef> Split = getTok().getIdentifier().split('@');
MCSymbol *Sym = CreateSymbol(Split.first);
+ // Mark the symbol as used in an expression.
+ Sym->setUsedInExpr(true);
+
// Lookup the symbol variant if used.
MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
if (Split.first.size() != getTok().getIdentifier().size())
@@ -199,11 +203,11 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
// If this is an absolute variable reference, substitute it now to preserve
// semantics in the face of reassignment.
- if (Sym->getValue() && isa<MCConstantExpr>(Sym->getValue())) {
+ if (Sym->isVariable() && isa<MCConstantExpr>(Sym->getVariableValue())) {
if (Variant)
return Error(EndLoc, "unexpected modified on variable reference");
- Res = Sym->getValue();
+ Res = Sym->getVariableValue();
return false;
}
@@ -211,11 +215,28 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
Res = MCSymbolRefExpr::Create(Sym, Variant, getContext());
return false;
}
- case AsmToken::Integer:
- Res = MCConstantExpr::Create(getTok().getIntVal(), getContext());
+ case AsmToken::Integer: {
+ SMLoc Loc = getTok().getLoc();
+ int64_t IntVal = getTok().getIntVal();
+ Res = MCConstantExpr::Create(IntVal, getContext());
EndLoc = Lexer.getLoc();
Lex(); // Eat token.
+ // Look for 'b' or 'f' following an Integer as a directional label
+ if (Lexer.getKind() == AsmToken::Identifier) {
+ StringRef IDVal = getTok().getString();
+ if (IDVal == "f" || IDVal == "b"){
+ MCSymbol *Sym = Ctx.GetDirectionalLocalSymbol(IntVal,
+ IDVal == "f" ? 1 : 0);
+ Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None,
+ getContext());
+ if(IDVal == "b" && Sym->isUndefined())
+ return Error(Loc, "invalid reference to undefined symbol");
+ EndLoc = Lexer.getLoc();
+ Lex(); // Eat identifier.
+ }
+ }
return false;
+ }
case AsmToken::Dot: {
// This is a '.' reference, which references the current PC. Emit a
// temporary label to the streamer and refer to it.
@@ -411,6 +432,7 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res,
/// ::= Label* Identifier OperandList* EndOfStatement
bool AsmParser::ParseStatement() {
if (Lexer.is(AsmToken::EndOfStatement)) {
+ Out.AddBlankLine();
Lex();
return false;
}
@@ -419,7 +441,25 @@ bool AsmParser::ParseStatement() {
AsmToken ID = getTok();
SMLoc IDLoc = ID.getLoc();
StringRef IDVal;
- if (ParseIdentifier(IDVal)) {
+ int64_t LocalLabelVal = -1;
+ // GUESS allow an integer followed by a ':' as a directional local label
+ if (Lexer.is(AsmToken::Integer)) {
+ LocalLabelVal = getTok().getIntVal();
+ if (LocalLabelVal < 0) {
+ if (!TheCondState.Ignore)
+ return TokError("unexpected token at start of statement");
+ IDVal = "";
+ }
+ else {
+ IDVal = getTok().getString();
+ Lex(); // Consume the integer token to be used as an identifier token.
+ if (Lexer.getKind() != AsmToken::Colon) {
+ if (!TheCondState.Ignore)
+ return TokError("unexpected token at start of statement");
+ }
+ }
+ }
+ else if (ParseIdentifier(IDVal)) {
if (!TheCondState.Ignore)
return TokError("unexpected token at start of statement");
IDVal = "";
@@ -456,13 +496,25 @@ bool AsmParser::ParseStatement() {
// FIXME: Diagnostics. Note the location of the definition as a label.
// FIXME: This doesn't diagnose assignment to a symbol which has been
// implicitly marked as external.
- MCSymbol *Sym = CreateSymbol(IDVal);
- if (!Sym->isUndefined())
+ MCSymbol *Sym;
+ if (LocalLabelVal == -1)
+ Sym = CreateSymbol(IDVal);
+ else
+ Sym = Ctx.CreateDirectionalLocalSymbol(LocalLabelVal);
+ if (!Sym->isUndefined() || Sym->isVariable())
return Error(IDLoc, "invalid symbol redefinition");
// Emit the label.
Out.EmitLabel(Sym);
+ // Consume any end of statement token, if present, to avoid spurious
+ // AddBlankLine calls().
+ if (Lexer.is(AsmToken::EndOfStatement)) {
+ Lex();
+ if (Lexer.is(AsmToken::Eof))
+ return false;
+ }
+
return ParseStatement();
}
@@ -620,6 +672,16 @@ bool AsmParser::ParseStatement() {
return ParseDirectiveSectionSwitch("__OBJC", "__selector_strs",
MCSectionMachO::S_CSTRING_LITERALS);
+ if (IDVal == ".tdata")
+ return ParseDirectiveSectionSwitch("__DATA", "__thread_data",
+ MCSectionMachO::S_THREAD_LOCAL_REGULAR);
+ if (IDVal == ".tlv")
+ return ParseDirectiveSectionSwitch("__DATA", "__thread_vars",
+ MCSectionMachO::S_THREAD_LOCAL_VARIABLES);
+ if (IDVal == ".thread_init_func")
+ return ParseDirectiveSectionSwitch("__DATA", "__thread_init",
+ MCSectionMachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+
// Assembler features
if (IDVal == ".set")
return ParseDirectiveSet();
@@ -686,6 +748,8 @@ bool AsmParser::ParseStatement() {
return ParseDirectiveSymbolAttribute(MCSA_Protected);
if (IDVal == ".reference")
return ParseDirectiveSymbolAttribute(MCSA_Reference);
+ if (IDVal == ".type")
+ return ParseDirectiveELFType();
if (IDVal == ".weak")
return ParseDirectiveSymbolAttribute(MCSA_Weak);
if (IDVal == ".weak_definition")
@@ -703,6 +767,8 @@ bool AsmParser::ParseStatement() {
return ParseDirectiveDarwinSymbolDesc();
if (IDVal == ".lsym")
return ParseDirectiveDarwinLsym();
+ if (IDVal == ".tbss")
+ return ParseDirectiveDarwinTBSS();
if (IDVal == ".subsections_via_symbols")
return ParseDirectiveDarwinSubsectionsViaSymbols();
@@ -729,8 +795,13 @@ bool AsmParser::ParseStatement() {
return false;
}
+ // Canonicalize the opcode to lower case.
+ SmallString<128> Opcode;
+ for (unsigned i = 0, e = IDVal.size(); i != e; ++i)
+ Opcode.push_back(tolower(IDVal[i]));
+
SmallVector<MCParsedAsmOperand*, 8> ParsedOperands;
- bool HadError = getTargetParser().ParseInstruction(IDVal, IDLoc,
+ bool HadError = getTargetParser().ParseInstruction(Opcode.str(), IDLoc,
ParsedOperands);
if (!HadError && Lexer.isNot(AsmToken::EndOfStatement))
HadError = TokError("unexpected token in argument list");
@@ -786,11 +857,13 @@ bool AsmParser::ParseAssignment(const StringRef &Name) {
//
// FIXME: Diagnostics. Note the location of the definition as a label.
// FIXME: Diagnose assignment to protected identifier (e.g., register name).
- if (!Sym->isUndefined() && !Sym->isAbsolute())
+ if (Sym->isUndefined() && !Sym->isUsedInExpr())
+ ; // Allow redefinitions of undefined symbols only used in directives.
+ else if (!Sym->isUndefined() && !Sym->isAbsolute())
return Error(EqualLoc, "redefinition of '" + Name + "'");
else if (!Sym->isVariable())
return Error(EqualLoc, "invalid assignment to '" + Name + "'");
- else if (!isa<MCConstantExpr>(Sym->getValue()))
+ else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
return Error(EqualLoc, "invalid reassignment of non-absolute variable '" +
Name + "'");
} else
@@ -798,6 +871,8 @@ bool AsmParser::ParseAssignment(const StringRef &Name) {
// FIXME: Handle '.'.
+ Sym->setUsedInExpr(true);
+
// Do the assignment.
Out.EmitAssignment(Sym, Value);
@@ -1008,7 +1083,11 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) {
if (ParseExpression(Value))
return true;
- Out.EmitValue(Value, Size, DEFAULT_ADDRSPACE);
+ // Special case constant expressions to match code generator.
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value))
+ Out.EmitIntValue(MCE->getValue(), Size, DEFAULT_ADDRSPACE);
+ else
+ Out.EmitValue(Value, Size, DEFAULT_ADDRSPACE);
if (Lexer.is(AsmToken::EndOfStatement))
break;
@@ -1090,8 +1169,7 @@ bool AsmParser::ParseDirectiveFill() {
return TokError("invalid '.fill' size, expected 1, 2, 4, or 8");
for (uint64_t i = 0, e = NumValues; i != e; ++i)
- Out.EmitValue(MCConstantExpr::Create(FillExpr, getContext()), FillSize,
- DEFAULT_ADDRSPACE);
+ Out.EmitIntValue(FillExpr, FillSize, DEFAULT_ADDRSPACE);
return false;
}
@@ -1169,10 +1247,8 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
Lex();
- if (!HasFillExpr) {
- // FIXME: Sometimes fill with nop.
+ if (!HasFillExpr)
FillExpr = 0;
- }
// Compute alignment in bytes.
if (IsPow2) {
@@ -1200,14 +1276,21 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
}
}
- // FIXME: hard code the parser to use EmitCodeAlignment for text when using
- // the TextAlignFillValue.
- if(Out.getCurrentSection()->getKind().isText() &&
- Lexer.getMAI().getTextAlignFillValue() == FillExpr)
+ // Check whether we should use optimal code alignment for this .align
+ // directive.
+ //
+ // FIXME: This should be using a target hook.
+ bool UseCodeAlign = false;
+ if (const MCSectionMachO *S = dyn_cast<MCSectionMachO>(
+ Out.getCurrentSection()))
+ UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS);
+ if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) &&
+ ValueSize == 1 && UseCodeAlign) {
Out.EmitCodeAlignment(Alignment, MaxBytesToFill);
- else
+ } else {
// FIXME: Target specific behavior about how the "extra" bytes are filled.
Out.EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill);
+ }
return false;
}
@@ -1239,6 +1322,52 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
return false;
}
+/// ParseDirectiveELFType
+/// ::= .type identifier , @attribute
+bool AsmParser::ParseDirectiveELFType() {
+ StringRef Name;
+ if (ParseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = CreateSymbol(Name);
+
+ if (Lexer.isNot(AsmToken::Comma))
+ return TokError("unexpected token in '.type' directive");
+ Lex();
+
+ if (Lexer.isNot(AsmToken::At))
+ return TokError("expected '@' before type");
+ Lex();
+
+ StringRef Type;
+ SMLoc TypeLoc;
+
+ TypeLoc = Lexer.getLoc();
+ if (ParseIdentifier(Type))
+ return TokError("expected symbol type in directive");
+
+ MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Type)
+ .Case("function", MCSA_ELF_TypeFunction)
+ .Case("object", MCSA_ELF_TypeObject)
+ .Case("tls_object", MCSA_ELF_TypeTLS)
+ .Case("common", MCSA_ELF_TypeCommon)
+ .Case("notype", MCSA_ELF_TypeNoType)
+ .Default(MCSA_Invalid);
+
+ if (Attr == MCSA_Invalid)
+ return Error(TypeLoc, "unsupported attribute in '.type' directive");
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.type' directive");
+
+ Lex();
+
+ Out.EmitSymbolAttribute(Sym, Attr);
+
+ return false;
+}
+
/// ParseDirectiveDarwinSymbolDesc
/// ::= .desc identifier , expression
bool AsmParser::ParseDirectiveDarwinSymbolDesc() {
@@ -1316,7 +1445,7 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) {
return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "
"be less than zero");
- // NOTE: The alignment in the directive is a power of 2 value, the assember
+ // NOTE: The alignment in the directive is a power of 2 value, the assembler
// may internally end up wanting an alignment in bytes.
// FIXME: Diagnose overflow.
if (Pow2Alignment < 0)
@@ -1344,22 +1473,18 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) {
/// ::= .zerofill segname , sectname [, identifier , size_expression [
/// , align_expression ]]
bool AsmParser::ParseDirectiveDarwinZerofill() {
- // FIXME: Handle quoted names here.
-
- if (Lexer.isNot(AsmToken::Identifier))
+ StringRef Segment;
+ if (ParseIdentifier(Segment))
return TokError("expected segment name after '.zerofill' directive");
- StringRef Segment = getTok().getString();
- Lex();
if (Lexer.isNot(AsmToken::Comma))
return TokError("unexpected token in directive");
Lex();
-
- if (Lexer.isNot(AsmToken::Identifier))
+
+ StringRef Section;
+ if (ParseIdentifier(Section))
return TokError("expected section name after comma in '.zerofill' "
"directive");
- StringRef Section = getTok().getString();
- Lex();
// If this is the end of the line all that was wanted was to create the
// the section but with no symbol.
@@ -1375,13 +1500,13 @@ bool AsmParser::ParseDirectiveDarwinZerofill() {
return TokError("unexpected token in directive");
Lex();
- if (Lexer.isNot(AsmToken::Identifier))
+ SMLoc IDLoc = Lexer.getLoc();
+ StringRef IDStr;
+ if (ParseIdentifier(IDStr))
return TokError("expected identifier in directive");
// handle the identifier as the key symbol.
- SMLoc IDLoc = Lexer.getLoc();
- MCSymbol *Sym = CreateSymbol(getTok().getString());
- Lex();
+ MCSymbol *Sym = CreateSymbol(IDStr);
if (Lexer.isNot(AsmToken::Comma))
return TokError("unexpected token in directive");
@@ -1410,7 +1535,7 @@ bool AsmParser::ParseDirectiveDarwinZerofill() {
return Error(SizeLoc, "invalid '.zerofill' directive size, can't be less "
"than zero");
- // NOTE: The alignment in the directive is a power of 2 value, the assember
+ // NOTE: The alignment in the directive is a power of 2 value, the assembler
// may internally end up wanting an alignment in bytes.
// FIXME: Diagnose overflow.
if (Pow2Alignment < 0)
@@ -1431,6 +1556,60 @@ bool AsmParser::ParseDirectiveDarwinZerofill() {
return false;
}
+/// ParseDirectiveDarwinTBSS
+/// ::= .tbss identifier, size, align
+bool AsmParser::ParseDirectiveDarwinTBSS() {
+ SMLoc IDLoc = Lexer.getLoc();
+ StringRef Name;
+ if (ParseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = CreateSymbol(Name);
+
+ if (Lexer.isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ int64_t Size;
+ SMLoc SizeLoc = Lexer.getLoc();
+ if (ParseAbsoluteExpression(Size))
+ return true;
+
+ int64_t Pow2Alignment = 0;
+ SMLoc Pow2AlignmentLoc;
+ if (Lexer.is(AsmToken::Comma)) {
+ Lex();
+ Pow2AlignmentLoc = Lexer.getLoc();
+ if (ParseAbsoluteExpression(Pow2Alignment))
+ return true;
+ }
+
+ if (Lexer.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.tbss' directive");
+
+ Lex();
+
+ if (Size < 0)
+ return Error(SizeLoc, "invalid '.tbss' directive size, can't be less than"
+ "zero");
+
+ // FIXME: Diagnose overflow.
+ if (Pow2Alignment < 0)
+ return Error(Pow2AlignmentLoc, "invalid '.tbss' alignment, can't be less"
+ "than zero");
+
+ if (!Sym->isUndefined())
+ return Error(IDLoc, "invalid symbol redefinition");
+
+ Out.EmitTBSSSymbol(Ctx.getMachOSection("__DATA", "__thread_bss",
+ MCSectionMachO::S_THREAD_LOCAL_ZEROFILL,
+ 0, SectionKind::getThreadBSS()),
+ Sym, Size, 1 << Pow2Alignment);
+
+ return false;
+}
+
/// ParseDirectiveDarwinSubsectionsViaSymbols
/// ::= .subsections_via_symbols
bool AsmParser::ParseDirectiveDarwinSubsectionsViaSymbols() {
diff --git a/lib/MC/MCSection.cpp b/lib/MC/MCSection.cpp
index f6e9636..a792d56 100644
--- a/lib/MC/MCSection.cpp
+++ b/lib/MC/MCSection.cpp
@@ -20,30 +20,3 @@ using namespace llvm;
MCSection::~MCSection() {
}
-//===----------------------------------------------------------------------===//
-// MCSectionCOFF
-//===----------------------------------------------------------------------===//
-
-MCSectionCOFF *MCSectionCOFF::
-Create(StringRef Name, bool IsDirective, SectionKind K, MCContext &Ctx) {
- char *NameCopy = static_cast<char*>(
- Ctx.Allocate(Name.size(), /*Alignment=*/1));
- memcpy(NameCopy, Name.data(), Name.size());
- return new (Ctx) MCSectionCOFF(StringRef(NameCopy, Name.size()),
- IsDirective, K);
-}
-
-void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI,
- raw_ostream &OS) const {
-
- if (isDirective()) {
- OS << getName() << '\n';
- return;
- }
- OS << "\t.section\t" << getName() << ",\"";
- if (getKind().isText())
- OS << 'x';
- if (getKind().isWriteable())
- OS << 'w';
- OS << "\"\n";
-}
diff --git a/lib/MC/MCSectionCOFF.cpp b/lib/MC/MCSectionCOFF.cpp
new file mode 100644
index 0000000..d57bb0c
--- /dev/null
+++ b/lib/MC/MCSectionCOFF.cpp
@@ -0,0 +1,76 @@
+//===- lib/MC/MCSectionCOFF.cpp - COFF Code Section Representation --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+MCSectionCOFF::~MCSectionCOFF() {} // anchor.
+
+// ShouldOmitSectionDirective - Decides whether a '.section' directive
+// should be printed before the section name
+bool MCSectionCOFF::ShouldOmitSectionDirective(StringRef Name,
+ const MCAsmInfo &MAI) const {
+
+ // FIXME: Does .section .bss/.data/.text work everywhere??
+ if (Name == ".text" || Name == ".data" || Name == ".bss")
+ return true;
+
+ return false;
+}
+
+void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI,
+ raw_ostream &OS) const {
+
+ // standard sections don't require the '.section'
+ if (ShouldOmitSectionDirective(SectionName, MAI)) {
+ OS << '\t' << getSectionName() << '\n';
+ return;
+ }
+
+ OS << "\t.section\t" << getSectionName() << ",\"";
+ if (getKind().isText())
+ OS << 'x';
+ if (getKind().isWriteable())
+ OS << 'w';
+ else
+ OS << 'r';
+ if (getCharacteristics() & MCSectionCOFF::IMAGE_SCN_MEM_DISCARDABLE)
+ OS << 'n';
+ OS << "\"\n";
+
+ if (getCharacteristics() & MCSectionCOFF::IMAGE_SCN_LNK_COMDAT) {
+ switch (Selection) {
+ case IMAGE_COMDAT_SELECT_NODUPLICATES:
+ OS << "\t.linkonce one_only\n";
+ break;
+ case IMAGE_COMDAT_SELECT_ANY:
+ OS << "\t.linkonce discard\n";
+ break;
+ case IMAGE_COMDAT_SELECT_SAME_SIZE:
+ OS << "\t.linkonce same_size\n";
+ break;
+ case IMAGE_COMDAT_SELECT_EXACT_MATCH:
+ OS << "\t.linkonce same_contents\n";
+ break;
+ //NOTE: as of binutils 2.20, there is no way to specifiy select largest
+ // with the .linkonce directive. For now, we treat it as an invalid
+ // comdat selection value.
+ case IMAGE_COMDAT_SELECT_LARGEST:
+ // OS << "\t.linkonce largest\n";
+ // break;
+ default:
+ assert (0 && "unsupported COFF selection type");
+ break;
+ }
+ }
+}
diff --git a/lib/MC/MCSectionMachO.cpp b/lib/MC/MCSectionMachO.cpp
index 3a18cee..ded3b20 100644
--- a/lib/MC/MCSectionMachO.cpp
+++ b/lib/MC/MCSectionMachO.cpp
@@ -34,7 +34,14 @@ static const struct {
{ "interposing", "S_INTERPOSING" }, // 0x0D
{ "16byte_literals", "S_16BYTE_LITERALS" }, // 0x0E
{ 0, /*FIXME??*/ "S_DTRACE_DOF" }, // 0x0F
- { 0, /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" } // 0x10
+ { 0, /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" }, // 0x10
+ { "thread_local_regular", "S_THREAD_LOCAL_REGULAR" }, // 0x11
+ { "thread_local_zerofill", "S_THREAD_LOCAL_ZEROFILL" }, // 0x12
+ { "thread_local_variables", "S_THREAD_LOCAL_VARIABLES" }, // 0x13
+ { "thread_local_variable_pointers",
+ "S_THREAD_LOCAL_VARIABLE_POINTERS" }, // 0x14
+ { "thread_local_init_function_pointers",
+ "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"}, // 0x15
};
@@ -66,7 +73,7 @@ ENTRY(0 /*FIXME*/, S_ATTR_LOC_RELOC)
MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section,
unsigned TAA, unsigned reserved2, SectionKind K)
- : MCSection(K), TypeAndAttributes(TAA), Reserved2(reserved2) {
+ : MCSection(SV_MachO, K), TypeAndAttributes(TAA), Reserved2(reserved2) {
assert(Segment.size() <= 16 && Section.size() <= 16 &&
"Segment or section string too long");
for (unsigned i = 0; i != 16; ++i) {
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 4f484a2..573f2a3 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
@@ -48,7 +48,7 @@ void MCStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue,
EmitValue(E, 1, AddrSpace);
}
-/// EmitRawText - If this file is backed by a assembly streamer, this dumps
+/// EmitRawText - If this file is backed by an assembly streamer, this dumps
/// the specified string in the output .s file. This capability is
/// indicated by the hasRawTextSupport() predicate.
void MCStreamer::EmitRawText(StringRef String) {
diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp
index 3fb1233..07751f7 100644
--- a/lib/MC/MCSymbol.cpp
+++ b/lib/MC/MCSymbol.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCExpr.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -38,6 +39,17 @@ static bool NameNeedsQuoting(StringRef Str) {
return false;
}
+void MCSymbol::setVariableValue(const MCExpr *Value) {
+ assert(Value && "Invalid variable value!");
+ assert((isUndefined() || (isAbsolute() && isa<MCConstantExpr>(Value))) &&
+ "Invalid redefinition!");
+ this->Value = Value;
+
+ // Mark the variable as absolute as appropriate.
+ if (isa<MCConstantExpr>(Value))
+ setAbsolute();
+}
+
void MCSymbol::print(raw_ostream &OS) const {
// The name for this MCSymbol is required to be a valid target name. However,
// some targets support quoting names with funny characters. If the name
diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp
index a533ccf..3207e99 100644
--- a/lib/MC/MachObjectWriter.cpp
+++ b/lib/MC/MachObjectWriter.cpp
@@ -16,6 +16,7 @@
#include "llvm/MC/MCObjectWriter.h"
#include "llvm/MC/MCSectionMachO.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCMachOSymbolFlags.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
@@ -58,6 +59,20 @@ static bool isFixupKindRIPRel(unsigned Kind) {
Kind == X86::reloc_riprel_4byte_movq_load;
}
+static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) {
+ // Undefined symbols are always extern.
+ if (SD->Symbol->isUndefined())
+ return true;
+
+ // References to weak definitions require external relocation entries; the
+ // definition may not always be the one in the same object file.
+ if (SD->getFlags() & SF_WeakDefinition)
+ return true;
+
+ // Otherwise, we can use an internal relocation.
+ return false;
+}
+
namespace {
class MachObjectWriterImpl {
@@ -130,7 +145,8 @@ class MachObjectWriterImpl {
RIT_Pair = 1,
RIT_Difference = 2,
RIT_PreboundLazyPointer = 3,
- RIT_LocalDifference = 4
+ RIT_LocalDifference = 4,
+ RIT_TLV = 5
};
/// X86_64 uses its own relocation types.
@@ -143,7 +159,8 @@ class MachObjectWriterImpl {
RIT_X86_64_Subtractor = 5,
RIT_X86_64_Signed1 = 6,
RIT_X86_64_Signed2 = 7,
- RIT_X86_64_Signed4 = 8
+ RIT_X86_64_Signed4 = 8,
+ RIT_X86_64_TLV = 9
};
/// MachSymbolData - Helper struct for containing some precomputed information
@@ -155,8 +172,8 @@ class MachObjectWriterImpl {
// Support lexicographic sorting.
bool operator<(const MachSymbolData &RHS) const {
- const std::string &Name = SymbolData->getSymbol().getName();
- return Name < RHS.SymbolData->getSymbol().getName();
+ return SymbolData->getSymbol().getName() <
+ RHS.SymbolData->getSymbol().getName();
}
};
@@ -170,6 +187,7 @@ class MachObjectWriterImpl {
llvm::DenseMap<const MCSectionData*,
std::vector<MachRelocationEntry> > Relocations;
+ llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase;
/// @}
/// @name Symbol Table Data
@@ -289,9 +307,7 @@ public:
uint64_t Start = OS.tell();
(void) Start;
- // FIXME: cast<> support!
- const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(SD.getSection());
+ const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection());
WriteBytes(Section.getSectionName(), 16);
WriteBytes(Section.getSegmentName(), 16);
if (Is64Bit) {
@@ -312,7 +328,7 @@ public:
Write32(NumRelocations ? RelocationsStart : 0);
Write32(NumRelocations);
Write32(Flags);
- Write32(0); // reserved1
+ Write32(IndirectSymBase.lookup(&SD)); // reserved1
Write32(Section.getStubSize()); // reserved2
if (Is64Bit)
Write32(0); // reserved3
@@ -404,7 +420,7 @@ public:
// Compute the symbol address.
if (Symbol.isDefined()) {
if (Symbol.isAbsolute()) {
- llvm_unreachable("FIXME: Not yet implemented!");
+ Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue();
} else {
Address = Layout.getSymbolAddress(&Data);
}
@@ -456,14 +472,17 @@ public:
void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
const MCFragment *Fragment,
- const MCAsmFixup &Fixup, MCValue Target,
+ const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
- unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
- unsigned IsRIPRel = isFixupKindRIPRel(Fixup.Kind);
- unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
+ unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+ unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind());
+ unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
// See <reloc.h>.
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupOffset =
+ Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+ uint32_t FixupAddress =
+ Layout.getFragmentAddress(Fragment) + Fixup.getOffset();
int64_t Value = 0;
unsigned Index = 0;
unsigned IsExtern = 0;
@@ -532,7 +551,7 @@ public:
Type = RIT_X86_64_Unsigned;
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |
@@ -548,6 +567,17 @@ public:
MCSymbolData &SD = Asm.getSymbolData(*Symbol);
const MCSymbolData *Base = Asm.getAtom(Layout, &SD);
+ // Relocations inside debug sections always use local relocations when
+ // possible. This seems to be done because the debugger doesn't fully
+ // understand x86_64 relocation entries, and expects to find values that
+ // have already been fixed up.
+ if (Symbol->isInSection()) {
+ const MCSectionMachO &Section = static_cast<const MCSectionMachO&>(
+ Fragment->getParent()->getSection());
+ if (Section.hasAttribute(MCSectionMachO::S_ATTR_DEBUG))
+ Base = 0;
+ }
+
// x86_64 almost always uses external relocations, except when there is no
// symbol to use as a base address (a local symbol with no preceeding
// non-local symbol).
@@ -558,14 +588,17 @@ public:
// Add the local offset, if needed.
if (Base != &SD)
Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base);
- } else {
+ } else if (Symbol->isInSection()) {
// The index is the section ordinal (1-based).
Index = SD.getFragment()->getParent()->getOrdinal() + 1;
IsExtern = 0;
Value += Layout.getSymbolAddress(&SD);
if (IsPCRel)
- Value -= Address + (1 << Log2Size);
+ Value -= FixupAddress + (1 << Log2Size);
+ } else {
+ report_fatal_error("unsupported relocation of undefined symbol '" +
+ Symbol->getName() + "'");
}
MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind();
@@ -575,14 +608,37 @@ public:
// x86_64 distinguishes movq foo@GOTPCREL so that the linker can
// rewrite the movq to an leaq at link time if the symbol ends up in
// the same linkage unit.
- if (unsigned(Fixup.Kind) == X86::reloc_riprel_4byte_movq_load)
+ if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load)
Type = RIT_X86_64_GOTLoad;
else
Type = RIT_X86_64_GOT;
- } else if (Modifier != MCSymbolRefExpr::VK_None)
+ } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
+ Type = RIT_X86_64_TLV;
+ } else if (Modifier != MCSymbolRefExpr::VK_None) {
report_fatal_error("unsupported symbol modifier in relocation");
- else
+ } else {
Type = RIT_X86_64_Signed;
+
+ // The Darwin x86_64 relocation format has a problem where it cannot
+ // encode an address (L<foo> + <constant>) which is outside the atom
+ // containing L<foo>. Generally, this shouldn't occur but it does
+ // happen when we have a RIPrel instruction with data following the
+ // relocation entry (e.g., movb $012, L0(%rip)). Even with the PCrel
+ // adjustment Darwin x86_64 uses, the offset is still negative and
+ // the linker has no way to recognize this.
+ //
+ // To work around this, Darwin uses several special relocation types
+ // to indicate the offsets. However, the specification or
+ // implementation of these seems to also be incomplete; they should
+ // adjust the addend as well based on the actual encoded instruction
+ // (the additional bias), but instead appear to just look at the
+ // final offset.
+ switch (-(Target.getConstant() + (1LL << Log2Size))) {
+ case 1: Type = RIT_X86_64_Signed1; break;
+ case 2: Type = RIT_X86_64_Signed2; break;
+ case 4: Type = RIT_X86_64_Signed4; break;
+ }
+ }
} else {
if (Modifier != MCSymbolRefExpr::VK_None)
report_fatal_error("unsupported symbol modifier in branch "
@@ -590,27 +646,6 @@ public:
Type = RIT_X86_64_Branch;
}
-
- // The Darwin x86_64 relocation format has a problem where it cannot
- // encode an address (L<foo> + <constant>) which is outside the atom
- // containing L<foo>. Generally, this shouldn't occur but it does happen
- // when we have a RIPrel instruction with data following the relocation
- // entry (e.g., movb $012, L0(%rip)). Even with the PCrel adjustment
- // Darwin x86_64 uses, the offset is still negative and the linker has
- // no way to recognize this.
- //
- // To work around this, Darwin uses several special relocation types to
- // indicate the offsets. However, the specification or implementation of
- // these seems to also be incomplete; they should adjust the addend as
- // well based on the actual encoded instruction (the additional bias),
- // but instead appear to just look at the final offset.
- if (IsRIPRel) {
- switch (-(Target.getConstant() + (1LL << Log2Size))) {
- case 1: Type = RIT_X86_64_Signed1; break;
- case 2: Type = RIT_X86_64_Signed2; break;
- case 4: Type = RIT_X86_64_Signed4; break;
- }
- }
} else {
if (Modifier == MCSymbolRefExpr::VK_GOT) {
Type = RIT_X86_64_GOT;
@@ -621,6 +656,8 @@ public:
// required to include any necessary offset directly.
Type = RIT_X86_64_GOT;
IsPCRel = 1;
+ } else if (Modifier == MCSymbolRefExpr::VK_TLVP) {
+ report_fatal_error("TLVP symbol modifier should have been rip-rel");
} else if (Modifier != MCSymbolRefExpr::VK_None)
report_fatal_error("unsupported symbol modifier in relocation");
else
@@ -633,7 +670,7 @@ public:
// struct relocation_info (8 bytes)
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |
@@ -645,11 +682,11 @@ public:
void RecordScatteredRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
- const MCAsmFixup &Fixup, MCValue Target,
+ const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
- unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
- unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
+ uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
+ unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+ unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
unsigned Type = RIT_Vanilla;
// See <reloc.h>.
@@ -692,40 +729,49 @@ public:
}
MachRelocationEntry MRE;
- MRE.Word0 = ((Address << 0) |
- (Type << 24) |
- (Log2Size << 28) |
- (IsPCRel << 30) |
+ MRE.Word0 = ((FixupOffset << 0) |
+ (Type << 24) |
+ (Log2Size << 28) |
+ (IsPCRel << 30) |
RF_Scattered);
MRE.Word1 = Value;
Relocations[Fragment->getParent()].push_back(MRE);
}
void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout,
- const MCFragment *Fragment, const MCAsmFixup &Fixup,
+ const MCFragment *Fragment, const MCFixup &Fixup,
MCValue Target, uint64_t &FixedValue) {
if (Is64Bit) {
RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue);
return;
}
- unsigned IsPCRel = isFixupKindPCRel(Fixup.Kind);
- unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind);
+ unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind());
+ unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind());
// If this is a difference or a defined symbol plus an offset, then we need
// a scattered relocation entry.
+ // Differences always require scattered relocations.
+ if (Target.getSymB())
+ return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,
+ Target, FixedValue);
+
+ // Get the symbol data, if any.
+ MCSymbolData *SD = 0;
+ if (Target.getSymA())
+ SD = &Asm.getSymbolData(Target.getSymA()->getSymbol());
+
+ // If this is an internal relocation with an offset, it also needs a
+ // scattered relocation entry.
uint32_t Offset = Target.getConstant();
if (IsPCRel)
Offset += 1 << Log2Size;
- if (Target.getSymB() ||
- (Target.getSymA() && !Target.getSymA()->getSymbol().isUndefined() &&
- Offset)) {
- RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,Target,FixedValue);
- return;
- }
+ if (Offset && SD && !doesSymbolRequireExternRelocation(SD))
+ return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup,
+ Target, FixedValue);
// See <reloc.h>.
- uint32_t Address = Layout.getFragmentOffset(Fragment) + Fixup.Offset;
+ uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset();
uint32_t Value = 0;
unsigned Index = 0;
unsigned IsExtern = 0;
@@ -739,12 +785,15 @@ public:
Type = RIT_Vanilla;
Value = 0;
} else {
- const MCSymbol *Symbol = &Target.getSymA()->getSymbol();
- MCSymbolData *SD = &Asm.getSymbolData(*Symbol);
-
- if (Symbol->isUndefined()) {
+ // Check whether we need an external or internal relocation.
+ if (doesSymbolRequireExternRelocation(SD)) {
IsExtern = 1;
Index = SD->getIndex();
+ // For external relocations, make sure to offset the fixup value to
+ // compensate for the addend of the symbol address, if it was
+ // undefined. This occurs with weak definitions, for example.
+ if (!SD->Symbol->isUndefined())
+ FixedValue -= Layout.getSymbolAddress(SD);
Value = 0;
} else {
// The index is the section ordinal (1-based).
@@ -757,7 +806,7 @@ public:
// struct relocation_info (8 bytes)
MachRelocationEntry MRE;
- MRE.Word0 = Address;
+ MRE.Word0 = FixupOffset;
MRE.Word1 = ((Index << 0) |
(IsPCRel << 24) |
(Log2Size << 25) |
@@ -775,29 +824,37 @@ public:
// FIXME: Revisit this when the dust settles.
// Bind non lazy symbol pointers first.
+ unsigned IndirectIndex = 0;
for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
- ie = Asm.indirect_symbol_end(); it != ie; ++it) {
- // FIXME: cast<> support!
+ ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) {
const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(it->SectionData->getSection());
+ cast<MCSectionMachO>(it->SectionData->getSection());
if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS)
continue;
+ // Initialize the section indirect symbol base, if necessary.
+ if (!IndirectSymBase.count(it->SectionData))
+ IndirectSymBase[it->SectionData] = IndirectIndex;
+
Asm.getOrCreateSymbolData(*it->Symbol);
}
// Then lazy symbol pointers and symbol stubs.
+ IndirectIndex = 0;
for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
- ie = Asm.indirect_symbol_end(); it != ie; ++it) {
- // FIXME: cast<> support!
+ ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) {
const MCSectionMachO &Section =
- static_cast<const MCSectionMachO&>(it->SectionData->getSection());
+ cast<MCSectionMachO>(it->SectionData->getSection());
if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS &&
Section.getType() != MCSectionMachO::S_SYMBOL_STUBS)
continue;
+ // Initialize the section indirect symbol base, if necessary.
+ if (!IndirectSymBase.count(it->SectionData))
+ IndirectSymBase[it->SectionData] = IndirectIndex;
+
// Set the symbol type to undefined lazy, but only on construction.
//
// FIXME: Do not hardcode.
@@ -1111,7 +1168,7 @@ void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) {
void MachObjectWriter::RecordRelocation(const MCAssembler &Asm,
const MCAsmLayout &Layout,
const MCFragment *Fragment,
- const MCAsmFixup &Fixup, MCValue Target,
+ const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) {
((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup,
Target, FixedValue);
OpenPOWER on IntegriCloud