Skip to content

Commit 3e9adff

Browse files
committed
[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.
1 parent bf60217 commit 3e9adff

File tree

5 files changed

+54
-66
lines changed

5 files changed

+54
-66
lines changed

lld/ELF/InputSection.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,9 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
13051305
break;
13061306
}
13071307
uint64_t size = endian::read32<ELFT::TargetEndianness>(d.data());
1308+
if (size == 0) // ZERO terminator
1309+
break;
1310+
uint32_t id = endian::read32<ELFT::TargetEndianness>(d.data() + 4);
13081311
// If it is 0xFFFFFFFF, the next 8 bytes contain the size instead,
13091312
// but we do not support that format yet.
13101313
if (size == UINT32_MAX) {
@@ -1318,7 +1321,7 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
13181321
}
13191322

13201323
uint64_t off = d.data() - rawData.data();
1321-
pieces.emplace_back(off, this, size, getReloc(off, size, rels, relI));
1324+
(id == 0 ? cies : fdes).emplace_back(off, this, size, getReloc(off, size, rels, relI));
13221325
d = d.slice(size);
13231326
}
13241327
if (msg)
@@ -1328,11 +1331,14 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
13281331

13291332
// Return the offset in an output section for a given input offset.
13301333
uint64_t EhInputSection::getParentOffset(uint64_t offset) const {
1331-
const EhSectionPiece &piece = partition_point(
1332-
pieces, [=](EhSectionPiece p) { return p.inputOff <= offset; })[-1];
1333-
if (piece.outputOff == -1) // invalid piece
1334-
return offset - piece.inputOff;
1335-
return piece.outputOff + (offset - piece.inputOff);
1334+
auto it = partition_point(
1335+
fdes, [=](EhSectionPiece p) { return p.inputOff <= offset; });
1336+
if (it == fdes.begin() || it[-1].inputOff + it[-1].size <= offset)
1337+
it = partition_point(
1338+
cies, [=](EhSectionPiece p) { return p.inputOff <= offset; });
1339+
if (it[-1].outputOff == -1) // invalid piece
1340+
return offset - it[-1].inputOff;
1341+
return it[-1].outputOff + (offset - it[-1].inputOff);
13361342
}
13371343

13381344
static size_t findNull(StringRef s, size_t entSize) {

lld/ELF/InputSection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ class EhInputSection : public InputSectionBase {
333333

334334
// Splittable sections are handled as a sequence of data
335335
// rather than a single large blob of data.
336-
SmallVector<EhSectionPiece, 0> pieces;
336+
SmallVector<EhSectionPiece, 0> cies, fdes;
337337

338338
SyntheticSection *getParent() const;
339339
uint64_t getParentOffset(uint64_t offset) const;

lld/ELF/MarkLive.cpp

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,20 +143,14 @@ template <class ELFT>
143143
template <class RelTy>
144144
void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh,
145145
ArrayRef<RelTy> rels) {
146-
for (size_t i = 0, end = eh.pieces.size(); i < end; ++i) {
147-
EhSectionPiece &piece = eh.pieces[i];
148-
size_t firstRelI = piece.firstRelocation;
146+
for (const EhSectionPiece &cie : eh.cies)
147+
if (cie.firstRelocation != unsigned(-1))
148+
resolveReloc(eh, rels[cie.firstRelocation], false);
149+
for (const EhSectionPiece &fde : eh.fdes) {
150+
size_t firstRelI = fde.firstRelocation;
149151
if (firstRelI == (unsigned)-1)
150152
continue;
151-
152-
if (read32<ELFT::TargetEndianness>(piece.data().data() + 4) == 0) {
153-
// This is a CIE, we only need to worry about the first relocation. It is
154-
// known to point to the personality function.
155-
resolveReloc(eh, rels[firstRelI], false);
156-
continue;
157-
}
158-
159-
uint64_t pieceEnd = piece.inputOff + piece.size;
153+
uint64_t pieceEnd = fde.inputOff + fde.size;
160154
for (size_t j = firstRelI, end2 = rels.size();
161155
j < end2 && rels[j].r_offset < pieceEnd; ++j)
162156
resolveReloc(eh, rels[j], true);

lld/ELF/Relocations.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,34 +397,41 @@ namespace {
397397
class OffsetGetter {
398398
public:
399399
explicit OffsetGetter(InputSectionBase &sec) {
400-
if (auto *eh = dyn_cast<EhInputSection>(&sec))
401-
pieces = eh->pieces;
400+
if (auto *eh = dyn_cast<EhInputSection>(&sec)) {
401+
cies = eh->cies;
402+
fdes = eh->fdes;
403+
i = cies.begin();
404+
j = fdes.begin();
405+
}
402406
}
403407

404408
// Translates offsets in input sections to offsets in output sections.
405409
// Given offset must increase monotonically. We assume that Piece is
406410
// sorted by inputOff.
407411
uint64_t get(uint64_t off) {
408-
if (pieces.empty())
412+
if (cies.empty())
409413
return off;
410414

411-
while (i != pieces.size() && pieces[i].inputOff + pieces[i].size <= off)
412-
++i;
413-
if (i == pieces.size())
414-
fatal(".eh_frame: relocation is not in any piece");
415-
416-
// Pieces must be contiguous, so there must be no holes in between.
417-
assert(pieces[i].inputOff <= off && "Relocation not in any piece");
415+
while (j != fdes.end() && j->inputOff <= off)
416+
++j;
417+
auto it = j;
418+
if (j == fdes.begin() || j[-1].inputOff + j[-1].size <= off) {
419+
while (i != cies.end() && i->inputOff <= off)
420+
++i;
421+
if (i == cies.begin() || i[-1].inputOff + i[-1].size <= off)
422+
fatal(".eh_frame: relocation is not in any piece");
423+
it = i;
424+
}
418425

419426
// Offset -1 means that the piece is dead (i.e. garbage collected).
420-
if (pieces[i].outputOff == -1)
427+
if (it[-1].outputOff == -1)
421428
return -1;
422-
return pieces[i].outputOff + off - pieces[i].inputOff;
429+
return it[-1].outputOff + (off - it[-1].inputOff);
423430
}
424431

425432
private:
426-
ArrayRef<EhSectionPiece> pieces;
427-
size_t i = 0;
433+
ArrayRef<EhSectionPiece> cies, fdes;
434+
ArrayRef<EhSectionPiece>::iterator i, j;
428435
};
429436

430437
// This class encapsulates states needed to scan relocations for one

lld/ELF/SyntheticSections.cpp

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -405,27 +405,17 @@ Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
405405
template <class ELFT, class RelTy>
406406
void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) {
407407
offsetToCie.clear();
408-
for (EhSectionPiece &piece : sec->pieces) {
409-
// The empty record is the end marker.
410-
if (piece.size == 4)
411-
return;
412-
413-
size_t offset = piece.inputOff;
414-
const uint32_t id =
415-
endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
416-
if (id == 0) {
417-
offsetToCie[offset] = addCie<ELFT>(piece, rels);
418-
continue;
419-
}
420-
421-
uint32_t cieOffset = offset + 4 - id;
422-
CieRecord *rec = offsetToCie[cieOffset];
408+
for (EhSectionPiece &cie : sec->cies)
409+
offsetToCie[cie.inputOff] = addCie<ELFT>(cie, rels);
410+
for (EhSectionPiece &fde : sec->fdes) {
411+
uint32_t id = endian::read32<ELFT::TargetEndianness>(fde.data().data() + 4);
412+
CieRecord *rec = offsetToCie[fde.inputOff + 4 - id];
423413
if (!rec)
424414
fatal(toString(sec) + ": invalid CIE reference");
425415

426-
if (!isFdeLive<ELFT>(piece, rels))
416+
if (!isFdeLive<ELFT>(fde, rels))
427417
continue;
428-
rec->fdes.push_back(&piece);
418+
rec->fdes.push_back(&fde);
429419
numFdes++;
430420
}
431421
}
@@ -457,25 +447,16 @@ template <class ELFT, class RelTy>
457447
void EhFrameSection::iterateFDEWithLSDAAux(
458448
EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA,
459449
llvm::function_ref<void(InputSection &)> fn) {
460-
for (EhSectionPiece &piece : sec.pieces) {
461-
// Skip ZERO terminator.
462-
if (piece.size == 4)
463-
continue;
464-
465-
size_t offset = piece.inputOff;
466-
uint32_t id =
467-
endian::read32<ELFT::TargetEndianness>(piece.data().data() + 4);
468-
if (id == 0) {
469-
if (hasLSDA(piece))
470-
ciesWithLSDA.insert(offset);
471-
continue;
472-
}
473-
uint32_t cieOffset = offset + 4 - id;
474-
if (ciesWithLSDA.count(cieOffset) == 0)
450+
for (EhSectionPiece &cie : sec.cies)
451+
if (hasLSDA(cie))
452+
ciesWithLSDA.insert(cie.inputOff);
453+
for (EhSectionPiece &fde : sec.fdes) {
454+
uint32_t id = endian::read32<ELFT::TargetEndianness>(fde.data().data() + 4);
455+
if (!ciesWithLSDA.contains(fde.inputOff + 4 - id))
475456
continue;
476457

477458
// The CIE has a LSDA argument. Call fn with d's section.
478-
if (Defined *d = isFdeLive<ELFT>(piece, rels))
459+
if (Defined *d = isFdeLive<ELFT>(fde, rels))
479460
if (auto *s = dyn_cast_or_null<InputSection>(d->section))
480461
fn(*s);
481462
}

0 commit comments

Comments
 (0)