Make it possible for the MCObjectWriter to decide if a given fixup is fully
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 30 Sep 2010 02:22:20 +0000 (02:22 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 30 Sep 2010 02:22:20 +0000 (02:22 +0000)
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

include/llvm/MC/ELFObjectWriter.h
include/llvm/MC/MCAssembler.h
include/llvm/MC/MCObjectWriter.h
include/llvm/MC/MachObjectWriter.h
lib/MC/ELFObjectWriter.cpp
lib/MC/MCAssembler.cpp
lib/MC/MachObjectWriter.cpp
lib/MC/WinCOFFObjectWriter.cpp
test/MC/ELF/relax.s [new file with mode: 0644]

index e5071066200de383d85a370e9cf9737869d02750..c8a42fe57b5cef6a067f58be3519ea67fa5ab319 100644 (file)
@@ -39,6 +39,11 @@ public:
                                 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);
 };
 
index 524f2abae28dededbcfcc5d58594855710667673..8d899d30d21bd813af6c414eb6c4fa401ae95ab8 100644 (file)
@@ -621,17 +621,19 @@ private:
   /// \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
@@ -642,7 +644,7 @@ private:
 
   /// 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);
@@ -664,7 +666,8 @@ public:
   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.
index f1c1cb8a5991715d5adfe0ff24e0d8e62694d395..7de37f762d365ea8c44efa95352bcb6d51ef58b9 100644 (file)
@@ -75,6 +75,16 @@ public:
                                 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
index 9b1ff1db8471a594e7f0156f9b1d4868d72bf278..198da8fc1736497ba875b605e5a34fb3f4a36044 100644 (file)
@@ -36,6 +36,11 @@ public:
                                 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);
 };
 
index b60271f1b2009a85b0c9a1c6c303e594c6d4d4e7..94251d76b285edf8cdfca8e08bc0b3810f89259b 100644 (file)
@@ -274,6 +274,11 @@ namespace {
     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);
   };
 
@@ -775,7 +780,7 @@ void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout,
 
     WriteRelocationsFragment(Asm, F, &SD);
 
-    Asm.AddSectionToTheEnd(RelaSD, Layout);
+    Asm.AddSectionToTheEnd(*Writer, RelaSD, Layout);
   }
 }
 
@@ -873,11 +878,11 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm,
   // 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);
 
@@ -903,7 +908,41 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm,
     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,
@@ -1064,6 +1103,14 @@ void ELFObjectWriter::RecordRelocation(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);
index 506f2a650a1eae0e4d11f99545c4242428505492..3d9dcba52d66b5b678619899343113d616ca2a6b 100644 (file)
@@ -232,89 +232,6 @@ MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend,
 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())
@@ -347,7 +264,8 @@ const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const {
   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;
@@ -377,31 +295,8 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout,
       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();
@@ -668,7 +563,8 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD,
   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)
@@ -697,7 +593,7 @@ void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) {
   Layout.LayoutSection(&SD);
 
   // Layout until everything fits.
-  while (LayoutOnce(Layout))
+  while (LayoutOnce(Writer, Layout))
     continue;
 
 }
@@ -756,8 +652,17 @@ void MCAssembler::Finish(MCObjectWriter *Writer) {
       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", {
@@ -773,15 +678,6 @@ void MCAssembler::Finish(MCObjectWriter *Writer) {
 
   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);
@@ -801,7 +697,7 @@ void MCAssembler::Finish(MCObjectWriter *Writer) {
         // 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.
@@ -819,7 +715,8 @@ void MCAssembler::Finish(MCObjectWriter *Writer) {
   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())
@@ -828,7 +725,7 @@ bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup,
   // 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.
@@ -837,7 +734,8 @@ bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup,
   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
@@ -847,13 +745,14 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF,
 
   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.
@@ -868,7 +767,7 @@ bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) {
            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;
index f81862e9ab11a5275583d2316f107330e6b18cd0..02a5575606dfde9451c4915ab3c44fe1dbda08fe 100644 (file)
@@ -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);
index 6bebe46f96b55ff2a4c8f2c5f307d839df6d09c0..1cc5c09a083879d9508b90003be1722b420af4cf 100644 (file)
@@ -181,6 +181,11 @@ public:
                         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);
 };
 }
@@ -690,6 +695,13 @@ 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 {
+  return false;
+}
+
 void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm,
                                       const MCAsmLayout &Layout) {
   // Assign symbol and section indexes and offsets.
diff --git a/test/MC/ELF/relax.s b/test/MC/ELF/relax.s
new file mode 100644 (file)
index 0000000..5c5e7e3
--- /dev/null
@@ -0,0 +1,38 @@
+// 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: ])