[lld] r276329 - Fix PR28575.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 21 13:18:31 PDT 2016


Author: rafael
Date: Thu Jul 21 15:18:30 2016
New Revision: 276329

URL: http://llvm.org/viewvc/llvm-project?rev=276329&view=rev
Log:
Fix PR28575.

Not all relocations from a .eh_frame that point to an executable
section should be ignored. In particular, the relocation finding the
personality function should not.

This is a reduction from trying to bootstrap a static lld on linux.

Added:
    lld/trunk/test/ELF/eh-frame-gc2.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/MarkLive.cpp
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu Jul 21 15:18:30 2016
@@ -443,14 +443,53 @@ bool EhInputSection<ELFT>::classof(const
   return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
 }
 
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+                         unsigned &RelocI) {
+  // Start search from RelocI for fast access. That works because the
+  // relocations are sorted in .eh_frame.
+  for (unsigned N = Rels.size(); RelocI < N; ++RelocI) {
+    const RelTy &Rel = Rels[RelocI];
+    if (Rel.r_offset < Begin)
+      continue;
+
+    if (Rel.r_offset < Begin + Size)
+      return RelocI;
+    return -1;
+  }
+  return -1;
+}
+
 // .eh_frame is a sequence of CIE or FDE records.
 // This function splits an input section into records and returns them.
 template <class ELFT>
 void EhInputSection<ELFT>::split() {
+  // Early exit if already split.
+  if (!this->Pieces.empty())
+    return;
+
+  if (RelocSection) {
+    ELFFile<ELFT> &Obj = this->File->getObj();
+    if (RelocSection->sh_type == SHT_RELA)
+      split(Obj.relas(RelocSection));
+    else
+      split(Obj.rels(RelocSection));
+    return;
+  }
+  split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+template <class RelTy>
+void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
   ArrayRef<uint8_t> Data = this->getSectionData();
+  unsigned RelI = 0;
   for (size_t Off = 0, End = Data.size(); Off != End;) {
     size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
-    this->Pieces.emplace_back(Off, Data.slice(Off, Size));
+    this->Pieces.emplace_back(Off, Data.slice(Off, Size),
+                              getReloc(Off, Size, Rels, RelI));
     // The empty record is the end marker.
     if (Size == 4)
       break;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Thu Jul 21 15:18:30 2016
@@ -149,6 +149,12 @@ private:
   llvm::DenseSet<uintX_t> LiveOffsets;
 };
 
+struct EhSectionPiece : public SectionPiece {
+  EhSectionPiece(size_t Off, ArrayRef<uint8_t> Data, unsigned FirstRelocation)
+      : SectionPiece(Off, Data), FirstRelocation(FirstRelocation) {}
+  unsigned FirstRelocation;
+};
+
 // This corresponds to a .eh_frame section of an input file.
 template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
 public:
@@ -157,10 +163,11 @@ public:
   EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
   static bool classof(const InputSectionBase<ELFT> *S);
   void split();
+  template <class RelTy> void split(ArrayRef<RelTy> Rels);
 
   // Splittable sections are handled as a sequence of data
   // rather than a single large blob of data.
-  std::vector<SectionPiece> Pieces;
+  std::vector<EhSectionPiece> Pieces;
 
   // Relocation section that refer to this one.
   const Elf_Shdr *RelocSection = nullptr;

Modified: lld/trunk/ELF/MarkLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/MarkLive.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/MarkLive.cpp (original)
+++ lld/trunk/ELF/MarkLive.cpp Thu Jul 21 15:18:30 2016
@@ -36,6 +36,7 @@
 using namespace llvm;
 using namespace llvm::ELF;
 using namespace llvm::object;
+using namespace llvm::support::endian;
 
 using namespace lld;
 using namespace lld::elf;
@@ -95,19 +96,70 @@ static void forEachSuccessor(InputSectio
     run(Obj, Sec, RelSec, Fn);
 }
 
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
+                   std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+  const endianness E = ELFT::TargetEndianness;
+  for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+    EhSectionPiece &Piece = EH.Pieces[I];
+    unsigned FirstRelI = Piece.FirstRelocation;
+    if (FirstRelI == (unsigned)-1)
+      continue;
+    if (read32<E>(Piece.data().data() + 4) == 0) {
+      // This is a CIE, we only need to worry about the first relocation. It is
+      // known to point to the personality function.
+      Enqueue(resolveReloc(EH, Rels[FirstRelI]));
+      continue;
+    }
+    // This is a FDE. The relocations point to the described function or to
+    // a LSDA. We only need to keep the LSDA alive, so ignore anything that
+    // points to executable sections.
+    typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size();
+    for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) {
+      const RelTy &Rel = Rels[I2];
+      if (Rel.r_offset >= PieceEnd)
+        break;
+      ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
+      if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+        continue;
+      if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
+        continue;
+      Enqueue({R.Sec, 0});
+    }
+  }
+}
+
 template <class ELFT>
-static void scanEhFrameSection(EhInputSection<ELFT> &EH,
-                               std::function<void(ResolvedReloc<ELFT>)> Fn) {
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH,
+                   std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
   if (!EH.RelocSection)
     return;
+
+  // Unfortunately we need to split .eh_frame early since some relocations in
+  // .eh_frame keep other section alive and some don't.
+  EH.split();
+
   ELFFile<ELFT> &EObj = EH.getFile()->getObj();
-  run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
-    if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
-      return;
-    if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
-      return;
-    Fn({R.Sec, 0});
-  });
+  if (EH.RelocSection->sh_type == SHT_RELA)
+    scanEhFrameSection(EH, EObj.relas(EH.RelocSection), Enqueue);
+  else
+    scanEhFrameSection(EH, EObj.rels(EH.RelocSection), Enqueue);
 }
 
 // Sections listed below are special because they are used by the loader

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Jul 21 15:18:30 2016
@@ -963,41 +963,22 @@ template <class ELFT>
 EhOutputSection<ELFT>::EhOutputSection()
     : OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
 
-// Returns the first relocation that points to a region
-// between Begin and Begin+Size.
-template <class IntTy, class RelTy>
-static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef<RelTy> &Rels) {
-  for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) {
-    if (I->r_offset < Begin)
-      continue;
-
-    // Truncate Rels for fast access. That means we expect that the
-    // relocations are sorted and we are looking up symbols in
-    // sequential order. It is naturally satisfied for .eh_frame.
-    Rels = Rels.slice(I - Rels.begin());
-    if (I->r_offset < Begin + Size)
-      return I;
-    return nullptr;
-  }
-  Rels = ArrayRef<RelTy>();
-  return nullptr;
-}
-
 // Search for an existing CIE record or create a new one.
 // CIE records from input object files are uniquified by their contents
 // and where their relocations point to.
 template <class ELFT>
 template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
+CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
                                          EhInputSection<ELFT> *Sec,
-                                         ArrayRef<RelTy> &Rels) {
+                                         ArrayRef<RelTy> Rels) {
   const endianness E = ELFT::TargetEndianness;
   if (read32<E>(Piece.data().data() + 4) != 0)
     fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
 
   SymbolBody *Personality = nullptr;
-  if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels))
-    Personality = &Sec->getFile()->getRelocTargetSym(*Rel);
+  unsigned FirstRelI = Piece.FirstRelocation;
+  if (FirstRelI != (unsigned)-1)
+    Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]);
 
   // Search for an existing CIE by CIE contents/relocation target pair.
   CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
@@ -1014,13 +995,14 @@ CieRecord *EhOutputSection<ELFT>::addCie
 // points to a live function.
 template <class ELFT>
 template <class RelTy>
-bool EhOutputSection<ELFT>::isFdeLive(SectionPiece &Piece,
+bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
                                       EhInputSection<ELFT> *Sec,
-                                      ArrayRef<RelTy> &Rels) {
-  const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels);
-  if (!Rel)
+                                      ArrayRef<RelTy> Rels) {
+  unsigned FirstRelI = Piece.FirstRelocation;
+  if (FirstRelI == (unsigned)-1)
     fatal("FDE doesn't reference another section");
-  SymbolBody &B = Sec->getFile()->getRelocTargetSym(*Rel);
+  const RelTy &Rel = Rels[FirstRelI];
+  SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel);
   auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
   if (!D || !D->Section)
     return false;
@@ -1039,7 +1021,7 @@ void EhOutputSection<ELFT>::addSectionAu
   const endianness E = ELFT::TargetEndianness;
 
   DenseMap<size_t, CieRecord *> OffsetToCie;
-  for (SectionPiece &Piece : Sec->Pieces) {
+  for (EhSectionPiece &Piece : Sec->Pieces) {
     // The empty record is the end marker.
     if (Piece.size() == 4)
       return;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Jul 21 15:18:30 2016
@@ -24,7 +24,7 @@ namespace lld {
 namespace elf {
 
 class SymbolBody;
-struct SectionPiece;
+struct EhSectionPiece;
 template <class ELFT> class SymbolTable;
 template <class ELFT> class SymbolTableSection;
 template <class ELFT> class StringTableSection;
@@ -372,8 +372,8 @@ private:
 };
 
 struct CieRecord {
-  SectionPiece *Piece = nullptr;
-  std::vector<SectionPiece *> FdePieces;
+  EhSectionPiece *Piece = nullptr;
+  std::vector<EhSectionPiece *> FdePieces;
 };
 
 // Output section for .eh_frame.
@@ -399,12 +399,12 @@ private:
   void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
 
   template <class RelTy>
-  CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
-                    ArrayRef<RelTy> &Rels);
+  CieRecord *addCie(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
+                    ArrayRef<RelTy> Rels);
 
   template <class RelTy>
-  bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
-                 ArrayRef<RelTy> &Rels);
+  bool isFdeLive(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
+                 ArrayRef<RelTy> Rels);
 
   uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
 

Added: lld/trunk/test/ELF/eh-frame-gc2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-gc2.s?rev=276329&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-gc2.s (added)
+++ lld/trunk/test/ELF/eh-frame-gc2.s Thu Jul 21 15:18:30 2016
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o
+// RUN: ld.lld --gc-sections %t.o -o %t
+// RUN: llvm-readobj -s %t | FileCheck %s
+
+// Test that the we don't gc the personality function.
+// CHECK: Name: .foobar
+
+	.globl	_start
+_start:
+	.cfi_startproc
+	.cfi_personality 3, foobar
+	.cfi_endproc
+        .section .foobar,"ax"
+foobar:




More information about the llvm-commits mailing list