diff options
Diffstat (limited to 'lib/MC/MachObjectWriter.cpp')
-rw-r--r-- | lib/MC/MachObjectWriter.cpp | 118 |
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); |