diff --git a/include/llvm/MC/MCObjectWriter.h b/include/llvm/MC/MCObjectWriter.h index 977b504a6ef..d267e6d0dfa 100644 --- a/include/llvm/MC/MCObjectWriter.h +++ b/include/llvm/MC/MCObjectWriter.h @@ -21,6 +21,7 @@ class MCAssembler; class MCFixup; class MCFragment; class MCSymbol; +class MCSymbolData; class MCSymbolRefExpr; class MCValue; class raw_ostream; @@ -84,21 +85,19 @@ public: /// /// Clients are not required to answer precisely and may conservatively return /// false, even when a difference is fully resolved. - virtual bool + bool IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, const MCSymbolRefExpr *A, const MCSymbolRefExpr *B, bool InSet) const; - /// 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; + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const = 0; + /// Write the object file. /// diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index b6e1223bc41..ef6e0f14141 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -344,10 +344,12 @@ namespace { MCDataFragment *F, const MCSectionData *SD); - virtual bool IsFixupFullyResolved(const MCAssembler &Asm, - const MCValue Target, - bool IsPCRel, - const MCFragment *DF) const; + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const; virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); virtual void WriteSection(MCAssembler &Asm, @@ -1154,50 +1156,22 @@ void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, } } -bool ELFObjectWriter::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->AliasedSymbol().getSection(); - } - - const MCSection *SectionB = 0; - const MCSymbol *SymbolB = 0; - if (const MCSymbolRefExpr *B = Target.getSymB()) { - SymbolB = &B->getSymbol(); - SectionB = &SymbolB->AliasedSymbol().getSection(); - } - - if (!BaseSection) - return SectionA == SectionB; - - if (SymbolB) - return false; - - // Absolute address but PCrel instruction, so we need a relocation. - if (!SymbolA) - return false; - +bool +ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { // FIXME: This is in here just to match gnu as output. If the two ends // are in the same section, there is nothing that the linker can do to // break it. - const MCSymbolData &DataA = Asm.getSymbolData(*SymbolA); if (DataA.isExternal()) return false; - return BaseSection == SectionA; + const MCSection &SecA = DataA.getSymbol().AliasedSymbol().getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + // On ELF A - B is absolute if A and B are in the same section. + return &SecA == &SecB; } void ELFObjectWriter::CreateGroupSections(MCAssembler &Asm, diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 3fd0c53c5ca..030ff987396 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -11,6 +11,7 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" @@ -218,22 +219,37 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &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 - // doesn't support small relocations, but then under what criteria does the - // assembler allow symbol differences? + bool IsPCRel = Backend.getFixupKindInfo( + Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + + bool IsResolved; + if (IsPCRel) { + if (Target.getSymB()) { + IsResolved = false; + } else if (!Target.getSymA()) { + IsResolved = false; + } else { + const MCSymbol &SA = Target.getSymA()->getSymbol(); + if (SA.AliasedSymbol().isUndefined()) { + IsResolved = false; + } else { + const MCSymbolData &DataA = getSymbolData(SA); + IsResolved = + getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA, + *DF, false, true); + } + } + } else { + IsResolved = Target.isAbsolute(); + } Value = Target.getConstant(); - bool IsPCRel = Backend.getFixupKindInfo( - Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; - bool IsResolved = true; bool IsThumb = false; if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); if (Sym.isDefined()) Value += Layout.getSymbolOffset(&getSymbolData(Sym)); - else - IsResolved = false; if (isThumbFunc(&Sym)) IsThumb = true; } @@ -241,12 +257,8 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, const MCSymbol &Sym = B->getSymbol().AliasedSymbol(); if (Sym.isDefined()) Value -= Layout.getSymbolOffset(&getSymbolData(Sym)); - else - IsResolved = false; } - if (IsResolved) - IsResolved = getWriter().IsFixupFullyResolved(*this, Target, IsPCRel, DF); bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp index e5f5f703289..f7a790410cd 100644 --- a/lib/MC/MCObjectWriter.cpp +++ b/lib/MC/MCObjectWriter.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSymbol.h" @@ -54,9 +55,14 @@ MCObjectWriter::IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, const MCSymbol &SA = A->getSymbol(); const MCSymbol &SB = B->getSymbol(); - if (SA.isUndefined() || SB.isUndefined()) + if (SA.AliasedSymbol().isUndefined() || SB.AliasedSymbol().isUndefined()) return false; - // On ELF and COFF A - B is absolute if A and B are in the same section. - return &SA.getSection() == &SB.getSection(); + const MCSymbolData &DataA = Asm.getSymbolData(SA); + const MCSymbolData &DataB = Asm.getSymbolData(SB); + + return IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, + *DataB.getFragment(), + InSet, + false); } diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index c8fe40e2f43..24ad99879f4 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -64,86 +64,6 @@ 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) + - // 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() + - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) - addr()) == 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 MachObjectWriter : public MCObjectWriter { @@ -1325,16 +1245,14 @@ public: UndefinedSymbolData); } - bool IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, - const MCSymbolRefExpr *A, - const MCSymbolRefExpr *B, - bool InSet) const { + virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { if (InSet) return true; - if (!TargetObjectWriter->useAggressiveSymbolFolding()) - return false; - // The effective address is // addr(atom(A)) + offset(A) // - addr(atom(B)) - offset(B) @@ -1342,16 +1260,38 @@ public: // addr(atom(A)) - addr(atom(B)) == 0. const MCSymbolData *A_Base = 0, *B_Base = 0; - // Modified symbol references cannot be resolved. - if (A->getKind() != MCSymbolRefExpr::VK_None || - B->getKind() != MCSymbolRefExpr::VK_None) - return false; + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + const MCSection &SecA = SA.getSection(); + const MCSection &SecB = FB.getParent()->getSection(); - A_Base = Asm.getAtom(&Asm.getSymbolData(A->getSymbol())); + if (IsPCRel) { + // 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. + + if (!Asm.getBackend().hasReliableSymbolDifference()) { + if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) + return false; + return true; + } + } else { + if (!TargetObjectWriter->useAggressiveSymbolFolding()) + return false; + } + + const MCFragment &FA = *Asm.getSymbolData(SA).getFragment(); + + A_Base = FA.getAtom(); if (!A_Base) return false; - B_Base = Asm.getAtom(&Asm.getSymbolData(B->getSymbol())); + B_Base = FB.getAtom(); if (!B_Base) return false; @@ -1363,37 +1303,6 @@ public: return false; } - bool IsFixupFullyResolved(const MCAssembler &Asm, - const MCValue Target, - bool IsPCRel, - const MCFragment *DF) const { - // Otherwise, determine whether this value is actually resolved; scattering - // may cause atoms to move. - - // Check if we are using the "simple" resolution algorithm (e.g., - // i386). - if (!Asm.getBackend().hasReliableSymbolDifference()) { - const MCSection *BaseSection = 0; - if (IsPCRel) - BaseSection = &DF->getParent()->getSection(); - - return isScatteredFixupFullyResolvedSimple(Asm, Target, BaseSection); - } - - // Otherwise, compute the proper answer as reliably as possible. - - // 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); - } - void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index 3a88a03f8bd..48a7c3bd64e 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -179,10 +179,12 @@ public: MCValue Target, uint64_t &FixedValue); - virtual bool IsFixupFullyResolved(const MCAssembler &Asm, - const MCValue Target, - bool IsPCRel, - const MCFragment *DF) const; + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const; void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); }; @@ -717,34 +719,17 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, coff_section->Relocations.push_back(Reloc); } -bool WinCOFFObjectWriter::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; - - return !SectionB && BaseSection == SectionA; +bool +WinCOFFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( + const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + const MCSection &SecA = DataA.getSymbol().AliasedSymbol().getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + // On COFF A - B is absolute if A and B are in the same section. + return &SecA == &SecB; } void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm,