const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue);
+ virtual bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const;
+
virtual void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout);
};
/// \return Whether the fixup value was fully resolved. This is true if the
/// \arg Value result is fixed, otherwise the value may change due to
/// relocation.
- bool EvaluateFixup(const MCAsmLayout &Layout,
+ bool EvaluateFixup(const MCObjectWriter &Writer, const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) const;
/// Check whether a fixup can be satisfied, or whether it needs to be relaxed
/// (increased in size, in order to hold its value correctly).
- bool FixupNeedsRelaxation(const MCFixup &Fixup, const MCFragment *DF,
+ bool FixupNeedsRelaxation(const MCObjectWriter &Writer,
+ const MCFixup &Fixup, const MCFragment *DF,
const MCAsmLayout &Layout) const;
/// Check whether the given fragment needs relaxation.
- bool FragmentNeedsRelaxation(const MCInstFragment *IF,
+ bool FragmentNeedsRelaxation(const MCObjectWriter &Writer,
+ const MCInstFragment *IF,
const MCAsmLayout &Layout) const;
/// Compute the effective fragment size assuming it is layed out at the given
/// LayoutOnce - Perform one layout iteration and return true if any offsets
/// were adjusted.
- bool LayoutOnce(MCAsmLayout &Layout);
+ bool LayoutOnce(const MCObjectWriter &Writer, MCAsmLayout &Layout);
/// FinishLayout - Finalize a layout, including fragment lowering.
void FinishLayout(MCAsmLayout &Layout);
void WriteSectionData(const MCSectionData *Section, const MCAsmLayout &Layout,
MCObjectWriter *OW) const;
- void AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout);
+ void AddSectionToTheEnd(const MCObjectWriter &Writer, MCSectionData &SD,
+ MCAsmLayout &Layout);
public:
/// Construct a new assembler instance.
const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue) = 0;
+ /// Check if a fixup is fully resolved.
+ ///
+ /// This routine is used by the assembler to let the file format decide
+ /// if a fixup is not fully resolved. For example, one that crosses
+ /// two sections on ELF.
+ virtual bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const = 0;
+
/// Write the object file.
///
/// This routine is called by the assembler after layout and relaxation is
const MCFixup &Fixup, MCValue Target,
uint64_t &FixedValue);
+ virtual bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const;
+
virtual void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout);
};
void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F,
const MCSectionData *SD);
+ bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const;
+
void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout);
};
WriteRelocationsFragment(Asm, F, &SD);
- Asm.AddSectionToTheEnd(RelaSD, Layout);
+ Asm.AddSectionToTheEnd(*Writer, RelaSD, Layout);
}
}
// Symbol table
F = new MCDataFragment(&SymtabSD);
WriteSymbolTable(F, Asm, Layout, NumRegularSections);
- Asm.AddSectionToTheEnd(SymtabSD, Layout);
+ Asm.AddSectionToTheEnd(*Writer, SymtabSD, Layout);
F = new MCDataFragment(&StrtabSD);
F->getContents().append(StringTable.begin(), StringTable.end());
- Asm.AddSectionToTheEnd(StrtabSD, Layout);
+ Asm.AddSectionToTheEnd(*Writer, StrtabSD, Layout);
F = new MCDataFragment(&ShstrtabSD);
F->getContents() += '\x00';
}
- Asm.AddSectionToTheEnd(ShstrtabSD, Layout);
+ Asm.AddSectionToTheEnd(*Writer, ShstrtabSD, Layout);
+}
+
+bool ELFObjectWriterImpl::IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const {
+ // If this is a PCrel relocation, find the section this fixup value is
+ // relative to.
+ const MCSection *BaseSection = 0;
+ if (IsPCRel) {
+ BaseSection = &DF->getParent()->getSection();
+ assert(BaseSection);
+ }
+
+ const MCSection *SectionA = 0;
+ const MCSymbol *SymbolA = 0;
+ if (const MCSymbolRefExpr *A = Target.getSymA()) {
+ SymbolA = &A->getSymbol();
+ SectionA = &SymbolA->getSection();
+ }
+
+ const MCSection *SectionB = 0;
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ SectionB = &B->getSymbol().getSection();
+ }
+
+ if (!BaseSection)
+ return SectionA == SectionB;
+
+ const MCSymbolData &DataA = Asm.getSymbolData(*SymbolA);
+ if (DataA.isExternal())
+ return false;
+
+ return !SectionB && BaseSection == SectionA;
}
void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm,
Target, FixedValue);
}
+bool ELFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const {
+ return ((ELFObjectWriterImpl*) Impl)->IsFixupFullyResolved(Asm, Target,
+ IsPCRel, DF);
+}
+
void ELFObjectWriter::WriteObject(const MCAssembler &Asm,
const MCAsmLayout &Layout) {
((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout);
MCAssembler::~MCAssembler() {
}
-static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm,
- const MCFixup &Fixup,
- const MCValue Target,
- const MCSection *BaseSection) {
- // The effective fixup address is
- // addr(atom(A)) + offset(A)
- // - addr(atom(B)) - offset(B)
- // - addr(<base symbol>) + <fixup offset from base symbol>
- // and the offsets are not relocatable, so the fixup is fully resolved when
- // addr(atom(A)) - addr(atom(B)) - addr(<base symbol>)) == 0.
- //
- // The simple (Darwin, except on x86_64) way of dealing with this was to
- // assume that any reference to a temporary symbol *must* be a temporary
- // symbol in the same atom, unless the sections differ. Therefore, any PCrel
- // relocation to a temporary symbol (in the same section) is fully
- // resolved. This also works in conjunction with absolutized .set, which
- // requires the compiler to use .set to absolutize the differences between
- // symbols which the compiler knows to be assembly time constants, so we don't
- // need to worry about considering symbol differences fully resolved.
-
- // Non-relative fixups are only resolved if constant.
- if (!BaseSection)
- return Target.isAbsolute();
-
- // Otherwise, relative fixups are only resolved if not a difference and the
- // target is a temporary in the same section.
- if (Target.isAbsolute() || Target.getSymB())
- return false;
-
- const MCSymbol *A = &Target.getSymA()->getSymbol();
- if (!A->isTemporary() || !A->isInSection() ||
- &A->getSection() != BaseSection)
- return false;
-
- return true;
-}
-
-static bool isScatteredFixupFullyResolved(const MCAssembler &Asm,
- const MCAsmLayout &Layout,
- const MCFixup &Fixup,
- const MCValue Target,
- const MCSymbolData *BaseSymbol) {
- // The effective fixup address is
- // addr(atom(A)) + offset(A)
- // - addr(atom(B)) - offset(B)
- // - addr(BaseSymbol) + <fixup offset from base symbol>
- // and the offsets are not relocatable, so the fixup is fully resolved when
- // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0.
- //
- // Note that "false" is almost always conservatively correct (it means we emit
- // a relocation which is unnecessary), except when it would force us to emit a
- // relocation which the target cannot encode.
-
- const MCSymbolData *A_Base = 0, *B_Base = 0;
- if (const MCSymbolRefExpr *A = Target.getSymA()) {
- // Modified symbol references cannot be resolved.
- if (A->getKind() != MCSymbolRefExpr::VK_None)
- return false;
-
- A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol()));
- if (!A_Base)
- return false;
- }
-
- if (const MCSymbolRefExpr *B = Target.getSymB()) {
- // Modified symbol references cannot be resolved.
- if (B->getKind() != MCSymbolRefExpr::VK_None)
- return false;
-
- B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol()));
- if (!B_Base)
- return false;
- }
-
- // If there is no base, A and B have to be the same atom for this fixup to be
- // fully resolved.
- if (!BaseSymbol)
- return A_Base == B_Base;
-
- // Otherwise, B must be missing and A must be the base.
- return !B_Base && BaseSymbol == A_Base;
-}
-
bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const {
// Non-temporary labels should always be visible to the linker.
if (!Symbol.isTemporary())
return SD->getFragment()->getAtom();
}
-bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
+bool MCAssembler::EvaluateFixup(const MCObjectWriter &Writer,
+ const MCAsmLayout &Layout,
const MCFixup &Fixup, const MCFragment *DF,
MCValue &Target, uint64_t &Value) const {
++stats::EvaluateFixup;
IsResolved = false;
}
- // If we are using scattered symbols, determine whether this value is actually
- // resolved; scattering may cause atoms to move.
- if (IsResolved && getBackend().hasScatteredSymbols()) {
- if (getBackend().hasReliableSymbolDifference()) {
- // If this is a PCrel relocation, find the base atom (identified by its
- // symbol) that the fixup value is relative to.
- const MCSymbolData *BaseSymbol = 0;
- if (IsPCRel) {
- BaseSymbol = DF->getAtom();
- if (!BaseSymbol)
- IsResolved = false;
- }
-
- if (IsResolved)
- IsResolved = isScatteredFixupFullyResolved(*this, Layout, Fixup, Target,
- BaseSymbol);
- } else {
- const MCSection *BaseSection = 0;
- if (IsPCRel)
- BaseSection = &DF->getParent()->getSection();
-
- IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, Target,
- BaseSection);
- }
- }
+ if (IsResolved)
+ IsResolved = Writer.IsFixupFullyResolved(*this, Target, IsPCRel, DF);
if (IsPCRel)
Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset();
assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD));
}
-void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) {
+void MCAssembler::AddSectionToTheEnd(const MCObjectWriter &Writer,
+ MCSectionData &SD, MCAsmLayout &Layout) {
// Create dummy fragments and assign section ordinals.
unsigned SectionIndex = 0;
for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it)
Layout.LayoutSection(&SD);
// Layout until everything fits.
- while (LayoutOnce(Layout))
+ while (LayoutOnce(Writer, Layout))
continue;
}
it2->setLayoutOrder(FragmentIndex++);
}
+ llvm::OwningPtr<MCObjectWriter> OwnWriter(0);
+ if (Writer == 0) {
+ //no custom Writer_ : create the default one life-managed by OwningPtr
+ OwnWriter.reset(getBackend().createObjectWriter(OS));
+ Writer = OwnWriter.get();
+ if (!Writer)
+ report_fatal_error("unable to create object writer!");
+ }
+
// Layout until everything fits.
- while (LayoutOnce(Layout))
+ while (LayoutOnce(*Writer, Layout))
continue;
DEBUG_WITH_TYPE("mc-dump", {
uint64_t StartOffset = OS.tell();
- llvm::OwningPtr<MCObjectWriter> OwnWriter(0);
- if (Writer == 0) {
- //no custom Writer_ : create the default one life-managed by OwningPtr
- OwnWriter.reset(getBackend().createObjectWriter(OS));
- Writer = OwnWriter.get();
- if (!Writer)
- report_fatal_error("unable to create object writer!");
- }
-
// Allow the object writer a chance to perform post-layout binding (for
// example, to set the index fields in the symbol data).
Writer->ExecutePostLayoutBinding(*this);
// Evaluate the fixup.
MCValue Target;
uint64_t FixedValue;
- if (!EvaluateFixup(Layout, Fixup, DF, Target, FixedValue)) {
+ if (!EvaluateFixup(*Writer, Layout, Fixup, DF, Target, FixedValue)) {
// The fixup was unresolved, we need a relocation. Inform the object
// writer of the relocation, and give it an opportunity to adjust the
// fixup value if need be.
stats::ObjectBytes += OS.tell() - StartOffset;
}
-bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup,
+bool MCAssembler::FixupNeedsRelaxation(const MCObjectWriter &Writer,
+ const MCFixup &Fixup,
const MCFragment *DF,
const MCAsmLayout &Layout) const {
if (getRelaxAll())
// If we cannot resolve the fixup value, it requires relaxation.
MCValue Target;
uint64_t Value;
- if (!EvaluateFixup(Layout, Fixup, DF, Target, Value))
+ if (!EvaluateFixup(Writer, Layout, Fixup, DF, Target, Value))
return true;
// Otherwise, relax if the value is too big for a (signed) i8.
return int64_t(Value) != int64_t(int8_t(Value));
}
-bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF,
+bool MCAssembler::FragmentNeedsRelaxation(const MCObjectWriter &Writer,
+ const MCInstFragment *IF,
const MCAsmLayout &Layout) const {
// 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
for (MCInstFragment::const_fixup_iterator it = IF->fixup_begin(),
ie = IF->fixup_end(); it != ie; ++it)
- if (FixupNeedsRelaxation(*it, IF, Layout))
+ if (FixupNeedsRelaxation(Writer, *it, IF, Layout))
return true;
return false;
}
-bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) {
+bool MCAssembler::LayoutOnce(const MCObjectWriter &Writer,
+ MCAsmLayout &Layout) {
++stats::RelaxationSteps;
// Layout the sections in order.
ie2 = SD.end(); it2 != ie2; ++it2) {
// Check if this is an instruction fragment that needs relaxation.
MCInstFragment *IF = dyn_cast<MCInstFragment>(it2);
- if (!IF || !FragmentNeedsRelaxation(IF, Layout))
+ if (!IF || !FragmentNeedsRelaxation(Writer, IF, Layout))
continue;
++stats::RelaxedInstructions;
return false;
}
+static bool isScatteredFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ const MCSymbolData *BaseSymbol) {
+ // The effective fixup address is
+ // addr(atom(A)) + offset(A)
+ // - addr(atom(B)) - offset(B)
+ // - addr(BaseSymbol) + <fixup offset from base symbol>
+ // and the offsets are not relocatable, so the fixup is fully resolved when
+ // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0.
+ //
+ // Note that "false" is almost always conservatively correct (it means we emit
+ // a relocation which is unnecessary), except when it would force us to emit a
+ // relocation which the target cannot encode.
+
+ const MCSymbolData *A_Base = 0, *B_Base = 0;
+ if (const MCSymbolRefExpr *A = Target.getSymA()) {
+ // Modified symbol references cannot be resolved.
+ if (A->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol()));
+ if (!A_Base)
+ return false;
+ }
+
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ // Modified symbol references cannot be resolved.
+ if (B->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol()));
+ if (!B_Base)
+ return false;
+ }
+
+ // If there is no base, A and B have to be the same atom for this fixup to be
+ // fully resolved.
+ if (!BaseSymbol)
+ return A_Base == B_Base;
+
+ // Otherwise, B must be missing and A must be the base.
+ return !B_Base && BaseSymbol == A_Base;
+}
+
+static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm,
+ const MCValue Target,
+ const MCSection *BaseSection) {
+ // The effective fixup address is
+ // addr(atom(A)) + offset(A)
+ // - addr(atom(B)) - offset(B)
+ // - addr(<base symbol>) + <fixup offset from base symbol>
+ // and the offsets are not relocatable, so the fixup is fully resolved when
+ // addr(atom(A)) - addr(atom(B)) - addr(<base symbol>)) == 0.
+ //
+ // The simple (Darwin, except on x86_64) way of dealing with this was to
+ // assume that any reference to a temporary symbol *must* be a temporary
+ // symbol in the same atom, unless the sections differ. Therefore, any PCrel
+ // relocation to a temporary symbol (in the same section) is fully
+ // resolved. This also works in conjunction with absolutized .set, which
+ // requires the compiler to use .set to absolutize the differences between
+ // symbols which the compiler knows to be assembly time constants, so we don't
+ // need to worry about considering symbol differences fully resolved.
+
+ // Non-relative fixups are only resolved if constant.
+ if (!BaseSection)
+ return Target.isAbsolute();
+
+ // Otherwise, relative fixups are only resolved if not a difference and the
+ // target is a temporary in the same section.
+ if (Target.isAbsolute() || Target.getSymB())
+ return false;
+
+ const MCSymbol *A = &Target.getSymA()->getSymbol();
+ if (!A->isTemporary() || !A->isInSection() ||
+ &A->getSection() != BaseSection)
+ return false;
+
+ return true;
+}
+
namespace {
class MachObjectWriterImpl {
UndefinedSymbolData);
}
+
+ bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const {
+ // If we are using scattered symbols, determine whether this value is
+ // actually resolved; scattering may cause atoms to move.
+ if (Asm.getBackend().hasScatteredSymbols()) {
+ if (Asm.getBackend().hasReliableSymbolDifference()) {
+ // If this is a PCrel relocation, find the base atom (identified by its
+ // symbol) that the fixup value is relative to.
+ const MCSymbolData *BaseSymbol = 0;
+ if (IsPCRel) {
+ BaseSymbol = DF->getAtom();
+ if (!BaseSymbol)
+ return false;
+ }
+
+ return isScatteredFixupFullyResolved(Asm, Target, BaseSymbol);
+ } else {
+ const MCSection *BaseSection = 0;
+ if (IsPCRel)
+ BaseSection = &DF->getParent()->getSection();
+
+ return isScatteredFixupFullyResolvedSimple(Asm, Target, BaseSection);
+ }
+ }
+ return true;
+ }
+
void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) {
unsigned NumSections = Asm.size();
Target, FixedValue);
}
+bool MachObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const {
+ return ((MachObjectWriterImpl*) Impl)->IsFixupFullyResolved(Asm, Target,
+ IsPCRel, DF);
+}
+
void MachObjectWriter::WriteObject(const MCAssembler &Asm,
const MCAsmLayout &Layout) {
((MachObjectWriterImpl*) Impl)->WriteObject(Asm, Layout);
MCValue Target,
uint64_t &FixedValue);
+ virtual bool IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const;
+
void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout);
};
}
coff_section->Relocations.push_back(Reloc);
}
+bool WinCOFFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm,
+ const MCValue Target,
+ bool IsPCRel,
+ const MCFragment *DF) const {
+ return false;
+}
+
void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm,
const MCAsmLayout &Layout) {
// Assign symbol and section indexes and offsets.
--- /dev/null
+// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | elf-dump --dump-section-data | FileCheck %s
+
+// Test that we do a relaxation for foo but not for bar. Relaxing foo is
+// probably not necessary, but matches what gnu as does.
+
+// Also test that the relaxation done for foo uses the symbol, not section and
+// offset.
+
+bar:
+.globl foo
+foo:
+ jmp bar
+ jmp foo
+
+// CHECK: ('sh_name', 1) # '.text'
+// CHECK-NEXT: ('sh_type', 1)
+// CHECK-NEXT: ('sh_flags', 6)
+// CHECK-NEXT: ('sh_addr', 0)
+// CHECK-NEXT: ('sh_offset', 64)
+// CHECK-NEXT: ('sh_size', 7)
+// CHECK-NEXT: ('sh_link', 0)
+// CHECK-NEXT: ('sh_info', 0)
+// CHECK-NEXT: ('sh_addralign', 4)
+// CHECK-NEXT: ('sh_entsize', 0)
+// CHECK-NEXT: ('_section_data', 'ebfee900 000000')
+
+// CHECK: # Symbol 5
+// CHECK-NEXT: (('st_name', 5) # 'foo'
+
+// CHECK: .rela.text
+// CHECK: ('_relocations', [
+// CHECK-NEXT: Relocation 0
+// CHECK-NEXT: (('r_offset', 3)
+// CHECK-NEXT: ('r_sym', 5)
+// CHECK-NEXT: ('r_type', 2)
+// CHECK-NEXT: ('r_addend', -4)
+// CHECK-NEXT: ),
+// CHECK-NEXT: ])