[lld] 3e9adff - [ELF] Split EhInputSection::pieces into cies and fdes

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Sun Jul 31 16:16:15 PDT 2022


Author: Fangrui Song
Date: 2022-07-31T16:16:10-07:00
New Revision: 3e9adff456213951376f6fff9349ffe71136f2b5

URL: https://github.com/llvm/llvm-project/commit/3e9adff456213951376f6fff9349ffe71136f2b5
DIFF: https://github.com/llvm/llvm-project/commit/3e9adff456213951376f6fff9349ffe71136f2b5.diff

LOG: [ELF] Split EhInputSection::pieces into cies and fdes

This simplifies code, removes a read32 (for id==0 check), and makes it feasible
to combine some operations in EhInputSection::split and EhFrameSection::addRecords.

Mostly NFC, but fixes "Relocation not in any piece" assertion failure in an
erroneous case when a relocation offset precedes all CIE/FDE pices.

Added: 
    

Modified: 
    lld/ELF/InputSection.cpp
    lld/ELF/InputSection.h
    lld/ELF/MarkLive.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/SyntheticSections.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index bfab457edfbd..f473e0ebe2ee 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -1305,6 +1305,9 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
       break;
     }
     uint64_t size = endian::read32<ELFT::TargetEndianness>(d.data());
+    if (size == 0) // ZERO terminator
+      break;
+    uint32_t id = endian::read32<ELFT::TargetEndianness>(d.data() + 4);
     // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
     // but we do not support that format yet.
     if (size == UINT32_MAX) {
@@ -1318,7 +1321,7 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
     }
 
     uint64_t off = d.data() - rawData.data();
-    pieces.emplace_back(off, this, size, getReloc(off, size, rels, relI));
+    (id == 0 ? cies : fdes).emplace_back(off, this, size, getReloc(off, size, rels, relI));
     d = d.slice(size);
   }
   if (msg)
@@ -1328,11 +1331,14 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
 
 // Return the offset in an output section for a given input offset.
 uint64_t EhInputSection::getParentOffset(uint64_t offset) const {
-  const EhSectionPiece &piece = partition_point(
-      pieces, [=](EhSectionPiece p) { return p.inputOff <= offset; })[-1];
-  if (piece.outputOff == -1) // invalid piece
-    return offset - piece.inputOff;
-  return piece.outputOff + (offset - piece.inputOff);
+  auto it = partition_point(
+      fdes, [=](EhSectionPiece p) { return p.inputOff <= offset; });
+  if (it == fdes.begin() || it[-1].inputOff + it[-1].size <= offset)
+    it = partition_point(
+        cies, [=](EhSectionPiece p) { return p.inputOff <= offset; });
+  if (it[-1].outputOff == -1) // invalid piece
+    return offset - it[-1].inputOff;
+  return it[-1].outputOff + (offset - it[-1].inputOff);
 }
 
 static size_t findNull(StringRef s, size_t entSize) {

diff  --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index b53119fcda02..2cdba943eb28 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -333,7 +333,7 @@ class EhInputSection : public InputSectionBase {
 
   // Splittable sections are handled as a sequence of data
   // rather than a single large blob of data.
-  SmallVector<EhSectionPiece, 0> pieces;
+  SmallVector<EhSectionPiece, 0> cies, fdes;
 
   SyntheticSection *getParent() const;
   uint64_t getParentOffset(uint64_t offset) const;

diff  --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index c7596d1293bb..c72b0409818b 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -143,20 +143,14 @@ template <class ELFT>
 template <class RelTy>
 void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh,
                                         ArrayRef<RelTy> rels) {
-  for (size_t i = 0, end = eh.pieces.size(); i < end; ++i) {
-    EhSectionPiece &piece = eh.pieces[i];
-    size_t firstRelI = piece.firstRelocation;
+  for (const EhSectionPiece &cie : eh.cies)
+    if (cie.firstRelocation != unsigned(-1))
+      resolveReloc(eh, rels[cie.firstRelocation], false);
+  for (const EhSectionPiece &fde : eh.fdes) {
+    size_t firstRelI = fde.firstRelocation;
     if (firstRelI == (unsigned)-1)
       continue;
-
-    if (read32<ELFT::TargetEndianness>(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.
-      resolveReloc(eh, rels[firstRelI], false);
-      continue;
-    }
-
-    uint64_t pieceEnd = piece.inputOff + piece.size;
+    uint64_t pieceEnd = fde.inputOff + fde.size;
     for (size_t j = firstRelI, end2 = rels.size();
          j < end2 && rels[j].r_offset < pieceEnd; ++j)
       resolveReloc(eh, rels[j], true);

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index e54e1ebd41bb..df33df4ae777 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -397,34 +397,41 @@ namespace {
 class OffsetGetter {
 public:
   explicit OffsetGetter(InputSectionBase &sec) {
-    if (auto *eh = dyn_cast<EhInputSection>(&sec))
-      pieces = eh->pieces;
+    if (auto *eh = dyn_cast<EhInputSection>(&sec)) {
+      cies = eh->cies;
+      fdes = eh->fdes;
+      i = cies.begin();
+      j = fdes.begin();
+    }
   }
 
   // Translates offsets in input sections to offsets in output sections.
   // Given offset must increase monotonically. We assume that Piece is
   // sorted by inputOff.
   uint64_t get(uint64_t off) {
-    if (pieces.empty())
+    if (cies.empty())
       return off;
 
-    while (i != pieces.size() && pieces[i].inputOff + pieces[i].size <= off)
-      ++i;
-    if (i == pieces.size())
-      fatal(".eh_frame: relocation is not in any piece");
-
-    // Pieces must be contiguous, so there must be no holes in between.
-    assert(pieces[i].inputOff <= off && "Relocation not in any piece");
+    while (j != fdes.end() && j->inputOff <= off)
+      ++j;
+    auto it = j;
+    if (j == fdes.begin() || j[-1].inputOff + j[-1].size <= off) {
+      while (i != cies.end() && i->inputOff <= off)
+        ++i;
+      if (i == cies.begin() || i[-1].inputOff + i[-1].size <= off)
+        fatal(".eh_frame: relocation is not in any piece");
+      it = i;
+    }
 
     // Offset -1 means that the piece is dead (i.e. garbage collected).
-    if (pieces[i].outputOff == -1)
+    if (it[-1].outputOff == -1)
       return -1;
-    return pieces[i].outputOff + off - pieces[i].inputOff;
+    return it[-1].outputOff + (off - it[-1].inputOff);
   }
 
 private:
-  ArrayRef<EhSectionPiece> pieces;
-  size_t i = 0;
+  ArrayRef<EhSectionPiece> cies, fdes;
+  ArrayRef<EhSectionPiece>::iterator i, j;
 };
 
 // This class encapsulates states needed to scan relocations for one

diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index f251bbcfcba0..af424d6ceead 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -405,27 +405,17 @@ Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
 template <class ELFT, class RelTy>
 void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) {
   offsetToCie.clear();
-  for (EhSectionPiece &piece : sec->pieces) {
-    // The empty record is the end marker.
-    if (piece.size == 4)
-      return;
-
-    size_t offset = piece.inputOff;
-    const uint32_t id =
-        endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
-    if (id == 0) {
-      offsetToCie[offset] = addCie<ELFT>(piece, rels);
-      continue;
-    }
-
-    uint32_t cieOffset = offset + 4 - id;
-    CieRecord *rec = offsetToCie[cieOffset];
+  for (EhSectionPiece &cie : sec->cies)
+    offsetToCie[cie.inputOff] = addCie<ELFT>(cie, rels);
+  for (EhSectionPiece &fde : sec->fdes) {
+    uint32_t id = endian::read32<ELFT::TargetEndianness>(fde.data().data() + 4);
+    CieRecord *rec = offsetToCie[fde.inputOff + 4 - id];
     if (!rec)
       fatal(toString(sec) + ": invalid CIE reference");
 
-    if (!isFdeLive<ELFT>(piece, rels))
+    if (!isFdeLive<ELFT>(fde, rels))
       continue;
-    rec->fdes.push_back(&piece);
+    rec->fdes.push_back(&fde);
     numFdes++;
   }
 }
@@ -457,25 +447,16 @@ template <class ELFT, class RelTy>
 void EhFrameSection::iterateFDEWithLSDAAux(
     EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA,
     llvm::function_ref<void(InputSection &)> fn) {
-  for (EhSectionPiece &piece : sec.pieces) {
-    // Skip ZERO terminator.
-    if (piece.size == 4)
-      continue;
-
-    size_t offset = piece.inputOff;
-    uint32_t id =
-        endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
-    if (id == 0) {
-      if (hasLSDA(piece))
-        ciesWithLSDA.insert(offset);
-      continue;
-    }
-    uint32_t cieOffset = offset + 4 - id;
-    if (ciesWithLSDA.count(cieOffset) == 0)
+  for (EhSectionPiece &cie : sec.cies)
+    if (hasLSDA(cie))
+      ciesWithLSDA.insert(cie.inputOff);
+  for (EhSectionPiece &fde : sec.fdes) {
+    uint32_t id = endian::read32<ELFT::TargetEndianness>(fde.data().data() + 4);
+    if (!ciesWithLSDA.contains(fde.inputOff + 4 - id))
       continue;
 
     // The CIE has a LSDA argument. Call fn with d's section.
-    if (Defined *d = isFdeLive<ELFT>(piece, rels))
+    if (Defined *d = isFdeLive<ELFT>(fde, rels))
       if (auto *s = dyn_cast_or_null<InputSection>(d->section))
         fn(*s);
   }


        


More information about the llvm-commits mailing list