Skip to content

Commit 3b299af

Browse files
authored
ELF: Store EhInputSection relocations to simplify code. NFC
Store relocations directly as `SmallVector<Relocation, 0>` within EhInputSection to avoid processing different relocation formats (REL/RELA/CREL) throughout the codebase. Next: Refactor RelocationScanner to utilize EhInputSection::rels Pull Request: #161041
1 parent a615249 commit 3b299af

File tree

5 files changed

+99
-100
lines changed

5 files changed

+99
-100
lines changed

lld/ELF/InputSection.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1358,20 +1358,21 @@ SyntheticSection *EhInputSection::getParent() const {
13581358
// .eh_frame is a sequence of CIE or FDE records.
13591359
// This function splits an input section into records and returns them.
13601360
template <class ELFT> void EhInputSection::split() {
1361-
const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>(/*supportsCrel=*/false);
1362-
// getReloc expects the relocations to be sorted by r_offset. See the comment
1363-
// in scanRelocs.
1364-
if (rels.areRelocsRel()) {
1365-
SmallVector<typename ELFT::Rel, 0> storage;
1366-
split<ELFT>(sortRels(rels.rels, storage));
1367-
} else {
1368-
SmallVector<typename ELFT::Rela, 0> storage;
1369-
split<ELFT>(sortRels(rels.relas, storage));
1370-
}
1371-
}
1361+
const RelsOrRelas<ELFT> elfRels = relsOrRelas<ELFT>();
1362+
if (elfRels.areRelocsCrel())
1363+
preprocessRelocs<ELFT>(elfRels.crels);
1364+
else if (elfRels.areRelocsRel())
1365+
preprocessRelocs<ELFT>(elfRels.rels);
1366+
else
1367+
preprocessRelocs<ELFT>(elfRels.relas);
1368+
1369+
// The loop below expects the relocations to be sorted by offset.
1370+
auto cmp = [](const Relocation &a, const Relocation &b) {
1371+
return a.offset < b.offset;
1372+
};
1373+
if (!llvm::is_sorted(rels, cmp))
1374+
llvm::stable_sort(rels, cmp);
13721375

1373-
template <class ELFT, class RelTy>
1374-
void EhInputSection::split(ArrayRef<RelTy> rels) {
13751376
ArrayRef<uint8_t> d = content();
13761377
const char *msg = nullptr;
13771378
unsigned relI = 0;
@@ -1397,10 +1398,10 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
13971398
// Find the first relocation that points to [off,off+size). Relocations
13981399
// have been sorted by r_offset.
13991400
const uint64_t off = d.data() - content().data();
1400-
while (relI != rels.size() && rels[relI].r_offset < off)
1401+
while (relI != rels.size() && rels[relI].offset < off)
14011402
++relI;
14021403
unsigned firstRel = -1;
1403-
if (relI != rels.size() && rels[relI].r_offset < off + size)
1404+
if (relI != rels.size() && rels[relI].offset < off + size)
14041405
firstRel = relI;
14051406
(id == 0 ? cies : fdes).emplace_back(off, this, size, firstRel);
14061407
d = d.slice(size);
@@ -1410,6 +1411,23 @@ void EhInputSection::split(ArrayRef<RelTy> rels) {
14101411
<< getObjMsg(d.data() - content().data());
14111412
}
14121413

1414+
template <class ELFT, class RelTy>
1415+
void EhInputSection::preprocessRelocs(Relocs<RelTy> elfRels) {
1416+
Ctx &ctx = file->ctx;
1417+
rels.reserve(elfRels.size());
1418+
for (auto rel : elfRels) {
1419+
uint64_t offset = rel.r_offset;
1420+
Symbol &sym = file->getSymbol(rel.getSymbol(ctx.arg.isMips64EL));
1421+
RelType type = rel.getType(ctx.arg.isMips64EL);
1422+
RelExpr expr = ctx.target->getRelExpr(type, sym, content().data() + offset);
1423+
int64_t addend =
1424+
RelTy::HasAddend
1425+
? getAddend<ELFT>(rel)
1426+
: ctx.target->getImplicitAddend(content().data() + offset, type);
1427+
rels.push_back({expr, type, offset, addend, &sym});
1428+
}
1429+
}
1430+
14131431
// Return the offset in an output section for a given input offset.
14141432
uint64_t EhInputSection::getParentOffset(uint64_t offset) const {
14151433
auto it = partition_point(

lld/ELF/InputSection.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,14 +394,18 @@ class EhInputSection : public InputSectionBase {
394394
StringRef name);
395395
static bool classof(const SectionBase *s) { return s->kind() == EHFrame; }
396396
template <class ELFT> void split();
397-
template <class ELFT, class RelTy> void split(ArrayRef<RelTy> rels);
397+
template <class ELFT, class RelTy> void preprocessRelocs(Relocs<RelTy> rels);
398398

399399
// Splittable sections are handled as a sequence of data
400400
// rather than a single large blob of data.
401401
SmallVector<EhSectionPiece, 0> cies, fdes;
402402

403403
SyntheticSection *getParent() const;
404404
uint64_t getParentOffset(uint64_t offset) const;
405+
406+
// Preprocessed relocations in uniform format to avoid REL/RELA/CREL
407+
// relocation format handling throughout the codebase.
408+
SmallVector<Relocation, 0> rels;
405409
};
406410

407411
// This is a section that is added directly to an output section

lld/ELF/MarkLive.cpp

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,9 @@ template <class ELFT, bool TrackWhyLive> class MarkLive {
6868
void mark();
6969

7070
template <class RelTy>
71-
void resolveReloc(InputSectionBase &sec, RelTy &rel, bool fromFDE);
71+
void resolveReloc(InputSectionBase &sec, const RelTy &rel, bool fromFDE);
7272

73-
template <class RelTy>
74-
void scanEhFrameSection(EhInputSection &eh, ArrayRef<RelTy> rels);
73+
void scanEhFrameSection(EhInputSection &eh);
7574

7675
Ctx &ctx;
7776
// The index of the partition that we are currently processing.
@@ -115,23 +114,38 @@ static uint64_t getAddend(Ctx &, InputSectionBase &sec,
115114
template <class ELFT, bool TrackWhyLive>
116115
template <class RelTy>
117116
void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec,
118-
RelTy &rel, bool fromFDE) {
117+
const RelTy &rel,
118+
bool fromFDE) {
119119
// If a symbol is referenced in a live section, it is used.
120-
Symbol &sym = sec.file->getRelocTargetSym(rel);
121-
sym.used = true;
120+
Symbol *sym;
121+
if constexpr (std::is_same_v<RelTy, Relocation>) {
122+
assert(isa<EhInputSection>(sec));
123+
sym = rel.sym;
124+
} else {
125+
sym = &sec.file->getRelocTargetSym(rel);
126+
}
127+
sym->used = true;
122128

123129
LiveReason reason;
124-
if (TrackWhyLive)
125-
reason = {SecOffset(&sec, rel.r_offset), "referenced by"};
130+
if (TrackWhyLive) {
131+
if constexpr (std::is_same_v<RelTy, Relocation>)
132+
reason = {SecOffset(&sec, rel.offset), "referenced by"};
133+
else
134+
reason = {SecOffset(&sec, rel.r_offset), "referenced by"};
135+
}
126136

127-
if (auto *d = dyn_cast<Defined>(&sym)) {
137+
if (auto *d = dyn_cast<Defined>(sym)) {
128138
auto *relSec = dyn_cast_or_null<InputSectionBase>(d->section);
129139
if (!relSec)
130140
return;
131141

132142
uint64_t offset = d->value;
133-
if (d->isSection())
134-
offset += getAddend<ELFT>(ctx, sec, rel);
143+
if (d->isSection()) {
144+
if constexpr (std::is_same_v<RelTy, Relocation>)
145+
offset += rel.addend;
146+
else
147+
offset += getAddend<ELFT>(ctx, sec, rel);
148+
}
135149

136150
// fromFDE being true means this is referenced by a FDE in a .eh_frame
137151
// piece. The relocation points to the described function or to a LSDA. We
@@ -141,8 +155,9 @@ void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec,
141155
// associated text section is live, the LSDA will be retained due to section
142156
// group/SHF_LINK_ORDER rules (b) if the associated text section should be
143157
// discarded, marking the LSDA will unnecessarily retain the text section.
144-
if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
145-
relSec->nextInSectionGroup))) {
158+
if (!(fromFDE && std::is_same_v<RelTy, Relocation> &&
159+
((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
160+
relSec->nextInSectionGroup))) {
146161
Symbol *canonicalSym = d;
147162
if (TrackWhyLive && d->isSection()) {
148163
// This is expensive, so ideally this would be deferred until it's known
@@ -159,15 +174,15 @@ void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec,
159174
return;
160175
}
161176

162-
if (auto *ss = dyn_cast<SharedSymbol>(&sym)) {
177+
if (auto *ss = dyn_cast<SharedSymbol>(sym)) {
163178
if (!ss->isWeak()) {
164179
cast<SharedFile>(ss->file)->isNeeded = true;
165180
if (TrackWhyLive)
166-
whyLive.try_emplace(&sym, reason);
181+
whyLive.try_emplace(sym, reason);
167182
}
168183
}
169184

170-
for (InputSectionBase *sec : cNamedSections.lookup(sym.getName()))
185+
for (InputSectionBase *sec : cNamedSections.lookup(sym->getName()))
171186
enqueue(sec, /*offset=*/0, /*sym=*/nullptr, reason);
172187
}
173188

@@ -186,9 +201,8 @@ void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec,
186201
// the gc pass. With that we would be able to also gc some sections holding
187202
// LSDAs and personality functions if we found that they were unused.
188203
template <class ELFT, bool TrackWhyLive>
189-
template <class RelTy>
190-
void MarkLive<ELFT, TrackWhyLive>::scanEhFrameSection(EhInputSection &eh,
191-
ArrayRef<RelTy> rels) {
204+
void MarkLive<ELFT, TrackWhyLive>::scanEhFrameSection(EhInputSection &eh) {
205+
ArrayRef<Relocation> rels = eh.rels;
192206
for (const EhSectionPiece &cie : eh.cies)
193207
if (cie.firstRelocation != unsigned(-1))
194208
resolveReloc(eh, rels[cie.firstRelocation], false);
@@ -198,7 +212,7 @@ void MarkLive<ELFT, TrackWhyLive>::scanEhFrameSection(EhInputSection &eh,
198212
continue;
199213
uint64_t pieceEnd = fde.inputOff + fde.size;
200214
for (size_t j = firstRelI, end2 = rels.size();
201-
j < end2 && rels[j].r_offset < pieceEnd; ++j)
215+
j < end2 && rels[j].offset < pieceEnd; ++j)
202216
resolveReloc(eh, rels[j], true);
203217
}
204218
}
@@ -360,14 +374,8 @@ void MarkLive<ELFT, TrackWhyLive>::run() {
360374
// that point to .eh_frames. Otherwise, the garbage collector would drop
361375
// all of them. We also want to preserve personality routines and LSDA
362376
// referenced by .eh_frame sections, so we scan them for that here.
363-
for (EhInputSection *eh : ctx.ehInputSections) {
364-
const RelsOrRelas<ELFT> rels =
365-
eh->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
366-
if (rels.areRelocsRel())
367-
scanEhFrameSection(*eh, rels.rels);
368-
else if (rels.relas.size())
369-
scanEhFrameSection(*eh, rels.relas);
370-
}
377+
for (EhInputSection *eh : ctx.ehInputSections)
378+
scanEhFrameSection(*eh);
371379
for (InputSectionBase *sec : ctx.inputSections) {
372380
if (sec->flags & SHF_GNU_RETAIN) {
373381
enqueue(sec, /*offset=*/0, /*sym=*/nullptr, {std::nullopt, "retained"});

lld/ELF/SyntheticSections.cpp

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -403,12 +403,12 @@ EhFrameSection::EhFrameSection(Ctx &ctx)
403403
// Search for an existing CIE record or create a new one.
404404
// CIE records from input object files are uniquified by their contents
405405
// and where their relocations point to.
406-
template <class RelTy>
407-
CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) {
406+
CieRecord *EhFrameSection::addCie(EhSectionPiece &cie,
407+
ArrayRef<Relocation> rels) {
408408
Symbol *personality = nullptr;
409409
unsigned firstRelI = cie.firstRelocation;
410410
if (firstRelI != (unsigned)-1)
411-
personality = &cie.sec->file->getRelocTargetSym(rels[firstRelI]);
411+
personality = rels[firstRelI].sym;
412412

413413
// Search for an existing CIE by CIE contents/relocation target pair.
414414
CieRecord *&rec = cieMap[{cie.data(), personality}];
@@ -424,25 +424,20 @@ CieRecord *EhFrameSection::addCie(EhSectionPiece &cie, ArrayRef<RelTy> rels) {
424424

425425
// There is one FDE per function. Returns a non-null pointer to the function
426426
// symbol if the given FDE points to a live function.
427-
template <class RelTy>
428-
Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
429-
auto *sec = cast<EhInputSection>(fde.sec);
430-
unsigned firstRelI = fde.firstRelocation;
431-
427+
Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde,
428+
ArrayRef<Relocation> rels) {
432429
// An FDE should point to some function because FDEs are to describe
433430
// functions. That's however not always the case due to an issue of
434431
// ld.gold with -r. ld.gold may discard only functions and leave their
435432
// corresponding FDEs, which results in creating bad .eh_frame sections.
436433
// To deal with that, we ignore such FDEs.
434+
unsigned firstRelI = fde.firstRelocation;
437435
if (firstRelI == (unsigned)-1)
438436
return nullptr;
439437

440-
const RelTy &rel = rels[firstRelI];
441-
Symbol &b = sec->file->getRelocTargetSym(rel);
442-
443438
// FDEs for garbage-collected or merged-by-ICF sections, or sections in
444439
// another partition, are dead.
445-
if (auto *d = dyn_cast<Defined>(&b))
440+
if (auto *d = dyn_cast<Defined>(rels[firstRelI].sym))
446441
if (!d->folded && d->section && d->section->partition == partition)
447442
return d;
448443
return nullptr;
@@ -452,13 +447,13 @@ Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde, ArrayRef<RelTy> rels) {
452447
// is one CIE record per input object file which is followed by
453448
// a list of FDEs. This function searches an existing CIE or create a new
454449
// one and associates FDEs to the CIE.
455-
template <class ELFT, class RelTy>
456-
void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) {
450+
template <endianness e> void EhFrameSection::addRecords(EhInputSection *sec) {
451+
auto rels = sec->rels;
457452
offsetToCie.clear();
458453
for (EhSectionPiece &cie : sec->cies)
459-
offsetToCie[cie.inputOff] = addCie<RelTy>(cie, rels);
454+
offsetToCie[cie.inputOff] = addCie(cie, rels);
460455
for (EhSectionPiece &fde : sec->fdes) {
461-
uint32_t id = endian::read32<ELFT::Endianness>(fde.data().data() + 4);
456+
uint32_t id = endian::read32<e>(fde.data().data() + 4);
462457
CieRecord *rec = offsetToCie[fde.inputOff + 4 - id];
463458
if (!rec)
464459
Fatal(ctx) << sec << ": invalid CIE reference";
@@ -470,23 +465,11 @@ void EhFrameSection::addRecords(EhInputSection *sec, ArrayRef<RelTy> rels) {
470465
}
471466
}
472467

473-
template <class ELFT>
474-
void EhFrameSection::addSectionAux(EhInputSection *sec) {
475-
if (!sec->isLive())
476-
return;
477-
const RelsOrRelas<ELFT> rels =
478-
sec->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
479-
if (rels.areRelocsRel())
480-
addRecords<ELFT>(sec, rels.rels);
481-
else
482-
addRecords<ELFT>(sec, rels.relas);
483-
}
484-
485468
// Used by ICF<ELFT>::handleLSDA(). This function is very similar to
486469
// EhFrameSection::addRecords().
487-
template <class ELFT, class RelTy>
470+
template <class ELFT>
488471
void EhFrameSection::iterateFDEWithLSDAAux(
489-
EhInputSection &sec, ArrayRef<RelTy> rels, DenseSet<size_t> &ciesWithLSDA,
472+
EhInputSection &sec, DenseSet<size_t> &ciesWithLSDA,
490473
llvm::function_ref<void(InputSection &)> fn) {
491474
for (EhSectionPiece &cie : sec.cies)
492475
if (hasLSDA(cie))
@@ -497,7 +480,7 @@ void EhFrameSection::iterateFDEWithLSDAAux(
497480
continue;
498481

499482
// The CIE has a LSDA argument. Call fn with d's section.
500-
if (Defined *d = isFdeLive(fde, rels))
483+
if (Defined *d = isFdeLive(fde, sec.rels))
501484
if (auto *s = dyn_cast_or_null<InputSection>(d->section))
502485
fn(*s);
503486
}
@@ -509,12 +492,7 @@ void EhFrameSection::iterateFDEWithLSDA(
509492
DenseSet<size_t> ciesWithLSDA;
510493
for (EhInputSection *sec : sections) {
511494
ciesWithLSDA.clear();
512-
const RelsOrRelas<ELFT> rels =
513-
sec->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
514-
if (rels.areRelocsRel())
515-
iterateFDEWithLSDAAux<ELFT>(*sec, rels.rels, ciesWithLSDA, fn);
516-
else
517-
iterateFDEWithLSDAAux<ELFT>(*sec, rels.relas, ciesWithLSDA, fn);
495+
iterateFDEWithLSDAAux<ELFT>(*sec, ciesWithLSDA, fn);
518496
}
519497
}
520498

@@ -531,20 +509,16 @@ void EhFrameSection::finalizeContents() {
531509
case ELFNoneKind:
532510
llvm_unreachable("invalid ekind");
533511
case ELF32LEKind:
534-
for (EhInputSection *sec : sections)
535-
addSectionAux<ELF32LE>(sec);
536-
break;
537-
case ELF32BEKind:
538-
for (EhInputSection *sec : sections)
539-
addSectionAux<ELF32BE>(sec);
540-
break;
541512
case ELF64LEKind:
542513
for (EhInputSection *sec : sections)
543-
addSectionAux<ELF64LE>(sec);
514+
if (sec->isLive())
515+
addRecords<endianness::little>(sec);
544516
break;
517+
case ELF32BEKind:
545518
case ELF64BEKind:
546519
for (EhInputSection *sec : sections)
547-
addSectionAux<ELF64BE>(sec);
520+
if (sec->isLive())
521+
addRecords<endianness::big>(sec);
548522
break;
549523
}
550524

lld/ELF/SyntheticSections.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,14 @@ class EhFrameSection final : public SyntheticSection {
8080

8181
uint64_t size = 0;
8282

83-
template <class ELFT, class RelTy>
84-
void addRecords(EhInputSection *s, llvm::ArrayRef<RelTy> rels);
85-
template <class ELFT> void addSectionAux(EhInputSection *s);
86-
template <class ELFT, class RelTy>
87-
void iterateFDEWithLSDAAux(EhInputSection &sec, ArrayRef<RelTy> rels,
83+
template <llvm::endianness E> void addRecords(EhInputSection *s);
84+
template <class ELFT>
85+
void iterateFDEWithLSDAAux(EhInputSection &sec,
8886
llvm::DenseSet<size_t> &ciesWithLSDA,
8987
llvm::function_ref<void(InputSection &)> fn);
9088

91-
template <class RelTy>
92-
CieRecord *addCie(EhSectionPiece &piece, ArrayRef<RelTy> rels);
93-
94-
template <class RelTy>
95-
Defined *isFdeLive(EhSectionPiece &piece, ArrayRef<RelTy> rels);
89+
CieRecord *addCie(EhSectionPiece &piece, ArrayRef<Relocation> rels);
90+
Defined *isFdeLive(EhSectionPiece &piece, ArrayRef<Relocation> rels);
9691

9792
uint64_t getFdePc(uint8_t *buf, size_t off, uint8_t enc) const;
9893

0 commit comments

Comments
 (0)