diff options
Diffstat (limited to 'lld/ELF/InputSection.cpp')
-rw-r--r-- | lld/ELF/InputSection.cpp | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 98267d1e..1270f27 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 <class ELFT> void EhInputSection::split() { - const RelsOrRelas<ELFT> rels = relsOrRelas<ELFT>(/*supportsCrel=*/false); - // getReloc expects the relocations to be sorted by r_offset. See the comment - // in scanRelocs. - if (rels.areRelocsRel()) { - SmallVector<typename ELFT::Rel, 0> storage; - split<ELFT>(sortRels(rels.rels, storage)); - } else { - SmallVector<typename ELFT::Rela, 0> storage; - split<ELFT>(sortRels(rels.relas, storage)); - } -} + const RelsOrRelas<ELFT> elfRels = relsOrRelas<ELFT>(); + if (elfRels.areRelocsCrel()) + preprocessRelocs<ELFT>(elfRels.crels); + else if (elfRels.areRelocsRel()) + preprocessRelocs<ELFT>(elfRels.rels); + else + preprocessRelocs<ELFT>(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 <class ELFT, class RelTy> -void EhInputSection::split(ArrayRef<RelTy> rels) { ArrayRef<uint8_t> d = content(); const char *msg = nullptr; unsigned relI = 0; @@ -1397,10 +1398,10 @@ void EhInputSection::split(ArrayRef<RelTy> 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<RelTy> rels) { << getObjMsg(d.data() - content().data()); } +template <class ELFT, class RelTy> +void EhInputSection::preprocessRelocs(Relocs<RelTy> 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<ELFT>(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( |