From 3b299af92383cb7558224482ccfa714f0162f772 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 29 Sep 2025 09:15:25 -0700 Subject: ELF: Store EhInputSection relocations to simplify code. NFC Store relocations directly as `SmallVector` within EhInputSection to avoid processing different relocation formats (REL/RELA/CREL) throughout the codebase. Next: Refactor RelocationScanner to utilize EhInputSection::rels Pull Request: https://github.com/llvm/llvm-project/pull/161041 --- lld/ELF/InputSection.cpp | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) (limited to 'lld/ELF/InputSection.cpp') diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 98267d1e081d..1270f27a8d96 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1358,20 +1358,21 @@ SyntheticSection *EhInputSection::getParent() const { // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. template void EhInputSection::split() { - const RelsOrRelas rels = relsOrRelas(/*supportsCrel=*/false); - // getReloc expects the relocations to be sorted by r_offset. See the comment - // in scanRelocs. - if (rels.areRelocsRel()) { - SmallVector storage; - split(sortRels(rels.rels, storage)); - } else { - SmallVector storage; - split(sortRels(rels.relas, storage)); - } -} + const RelsOrRelas elfRels = relsOrRelas(); + if (elfRels.areRelocsCrel()) + preprocessRelocs(elfRels.crels); + else if (elfRels.areRelocsRel()) + preprocessRelocs(elfRels.rels); + else + preprocessRelocs(elfRels.relas); + + // The loop below expects the relocations to be sorted by offset. + auto cmp = [](const Relocation &a, const Relocation &b) { + return a.offset < b.offset; + }; + if (!llvm::is_sorted(rels, cmp)) + llvm::stable_sort(rels, cmp); -template -void EhInputSection::split(ArrayRef rels) { ArrayRef d = content(); const char *msg = nullptr; unsigned relI = 0; @@ -1397,10 +1398,10 @@ void EhInputSection::split(ArrayRef rels) { // Find the first relocation that points to [off,off+size). Relocations // have been sorted by r_offset. const uint64_t off = d.data() - content().data(); - while (relI != rels.size() && rels[relI].r_offset < off) + while (relI != rels.size() && rels[relI].offset < off) ++relI; unsigned firstRel = -1; - if (relI != rels.size() && rels[relI].r_offset < off + size) + if (relI != rels.size() && rels[relI].offset < off + size) firstRel = relI; (id == 0 ? cies : fdes).emplace_back(off, this, size, firstRel); d = d.slice(size); @@ -1410,6 +1411,23 @@ void EhInputSection::split(ArrayRef rels) { << getObjMsg(d.data() - content().data()); } +template +void EhInputSection::preprocessRelocs(Relocs elfRels) { + Ctx &ctx = file->ctx; + rels.reserve(elfRels.size()); + for (auto rel : elfRels) { + uint64_t offset = rel.r_offset; + Symbol &sym = file->getSymbol(rel.getSymbol(ctx.arg.isMips64EL)); + RelType type = rel.getType(ctx.arg.isMips64EL); + RelExpr expr = ctx.target->getRelExpr(type, sym, content().data() + offset); + int64_t addend = + RelTy::HasAddend + ? getAddend(rel) + : ctx.target->getImplicitAddend(content().data() + offset, type); + rels.push_back({expr, type, offset, addend, &sym}); + } +} + // Return the offset in an output section for a given input offset. uint64_t EhInputSection::getParentOffset(uint64_t offset) const { auto it = partition_point( -- cgit v1.2.3 From 3554c78d973477835b0b062a8aa16ecbc62446dd Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Mon, 29 Sep 2025 20:39:49 -0700 Subject: ELF: Use preprocessed relocations for EhInputSection scanning .eh_frame sections require special sub-section processing, specifically, CIEs are de-duplicated and FDEs are garbage collected. Create a specialized scanEhSection() function utilizing the just-added EhInputSection::rels. OffsetGetter is moved to scanEhSection. This improves separation of concerns between InputSection and EhInputSection processing. This removes another `relsOrRelas` call using `supportsCrel=false`. DWARF.cpp now has the last call. Pull Request: https://github.com/llvm/llvm-project/pull/161091 --- lld/ELF/InputSection.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lld/ELF/InputSection.cpp') diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 1270f27a8d96..ff7ef2dce5c7 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -1357,6 +1357,8 @@ SyntheticSection *EhInputSection::getParent() const { // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. +// In rare cases (.eh_frame pieces are reordered by a linker script), the +// relocations may be unordered. template void EhInputSection::split() { const RelsOrRelas elfRels = relsOrRelas(); if (elfRels.areRelocsCrel()) -- cgit v1.2.3