[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