aboutsummaryrefslogtreecommitdiff
path: root/lib/MC/MachObjectWriter.cpp
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2010-09-30 02:22:20 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2010-09-30 02:22:20 +0000
commit7070387f08f7dc797b554ed8013cba9f8b74121a (patch)
treeb2551756c1093c8e4396c9c2596eca5f8657fd51 /lib/MC/MachObjectWriter.cpp
parent7ebc863c156c5ccd127045ddb8d663c3b49ac5f3 (diff)
Make it possible for the MCObjectWriter to decide if a given fixup is fully
resolved or not. Different object files have different restrictions and different native assemblers have different idiosyncrasies we want to emulate for now. Move the existing MachO logic to the new place and implement an ELF one that gets fixups to globals right. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@115131 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/MC/MachObjectWriter.cpp')
-rw-r--r--lib/MC/MachObjectWriter.cpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp
index f81862e9ab..02a5575606 100644
--- a/lib/MC/MachObjectWriter.cpp
+++ b/lib/MC/MachObjectWriter.cpp
@@ -75,6 +75,86 @@ static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) {
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 {
@@ -1038,6 +1118,36 @@ public:
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();
@@ -1224,6 +1334,14 @@ void MachObjectWriter::RecordRelocation(const MCAssembler &Asm,
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);