From 9f0c4bb795f4b194b8597b594c82279d906159c0 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Thu, 10 Nov 2016 14:53:24 +0000 Subject: [PATCH] Parse relocations only once. Relocations are the last thing that we wore storing a raw section pointer to and parsing on demand. With this patch we parse it only once and store a pointer to the actual data. The patch also changes where we store it. It is now in InputSectionBase. Not all sections have relocations, but most do and this simplifies the logic. It also means that we now only support one relocation section per section. Given that that constraint is maintained even with -r with gold bfd and lld, I think it is OK. llvm-svn: 286459 --- lld/ELF/ICF.cpp | 42 +++++++----------------- lld/ELF/InputFiles.cpp | 33 ++++++++++++------- lld/ELF/InputFiles.h | 2 ++ lld/ELF/InputSection.cpp | 22 ++++++------- lld/ELF/InputSection.h | 24 ++++++++++---- lld/ELF/MarkLive.cpp | 24 ++++++-------- lld/ELF/OutputSections.cpp | 9 +++--- lld/ELF/Relocations.cpp | 46 ++++++++++----------------- lld/ELF/Relocations.h | 6 ++-- lld/ELF/Writer.cpp | 16 +++------- lld/test/ELF/invalid/invalid-elf.test | 2 +- 11 files changed, 100 insertions(+), 126 deletions(-) diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp index a3e098082f30..5f6b41ef739d 100644 --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -120,10 +120,7 @@ private: // relocation targets is not included in the hash value. template uint64_t ICF::getHash(InputSection *S) { uint64_t Flags = S->Flags; - uint64_t H = hash_combine(Flags, S->getSize()); - for (const Elf_Shdr *Rel : S->RelocSections) - H = hash_combine(H, (uint64_t)Rel->sh_size); - return H; + return hash_combine(Flags, S->getSize(), S->NumRelocations); } // Returns true if Sec is subject of ICF. @@ -212,21 +209,15 @@ bool ICF::relocationEq(ArrayRef RelsA, ArrayRef RelsB) { template bool ICF::equalsConstant(const InputSection *A, const InputSection *B) { - if (A->RelocSections.size() != B->RelocSections.size()) + if (A->NumRelocations != B->NumRelocations) return false; - for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) { - const Elf_Shdr *RA = A->RelocSections[I]; - const Elf_Shdr *RB = B->RelocSections[I]; - ELFFile FileA = A->getObj(); - ELFFile FileB = B->getObj(); - if (RA->sh_type == SHT_RELA) { - if (!relocationEq(check(FileA.relas(RA)), check(FileB.relas(RB)))) - return false; - } else { - if (!relocationEq(check(FileA.rels(RA)), check(FileB.rels(RB)))) - return false; - } + if (A->AreRelocsRela) { + if (!relocationEq(A->relas(), B->relas())) + return false; + } else { + if (!relocationEq(A->rels(), B->rels())) + return false; } return A->Flags == B->Flags && A->getSize() == B->getSize() && @@ -268,20 +259,9 @@ bool ICF::variableEq(const InputSection *A, template bool ICF::equalsVariable(const InputSection *A, const InputSection *B) { - for (size_t I = 0, E = A->RelocSections.size(); I != E; ++I) { - const Elf_Shdr *RA = A->RelocSections[I]; - const Elf_Shdr *RB = B->RelocSections[I]; - ELFFile FileA = A->getObj(); - ELFFile FileB = B->getObj(); - if (RA->sh_type == SHT_RELA) { - if (!variableEq(A, B, check(FileA.relas(RA)), check(FileB.relas(RB)))) - return false; - } else { - if (!variableEq(A, B, check(FileA.rels(RA)), check(FileB.rels(RB)))) - return false; - } - } - return true; + if (A->AreRelocsRela) + return variableEq(A, B, A->relas(), B->relas()); + return variableEq(A, B, A->rels(), B->rels()); } // The main function of ICF. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 340c98e57923..3eb89097d694 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -353,19 +353,28 @@ elf::ObjectFile::createInputSection(const Elf_Shdr &Sec, InputSectionBase *Target = getRelocTarget(Sec); if (!Target) return nullptr; - if (auto *S = dyn_cast>(Target)) { - S->RelocSections.push_back(&Sec); - return nullptr; + if (Target->FirstRelocation) + fatal(getFilename(this) + + ": multiple relocation sections to one section are not supported"); + if (!isa>(Target) && !isa>(Target)) + fatal(getFilename(this) + + ": relocations pointing to SHF_MERGE are not supported"); + + size_t NumRelocations; + if (Sec.sh_type == SHT_RELA) { + ArrayRef Rels = check(this->getObj().relas(&Sec)); + Target->FirstRelocation = Rels.begin(); + NumRelocations = Rels.size(); + Target->AreRelocsRela = true; + } else { + ArrayRef Rels = check(this->getObj().rels(&Sec)); + Target->FirstRelocation = Rels.begin(); + NumRelocations = Rels.size(); + Target->AreRelocsRela = false; } - if (auto *S = dyn_cast>(Target)) { - if (S->RelocSection) - fatal(getFilename(this) + - ": multiple relocation sections to .eh_frame are not supported"); - S->RelocSection = &Sec; - return nullptr; - } - fatal(getFilename(this) + - ": relocations pointing to SHF_MERGE are not supported"); + assert(isUInt<31>(NumRelocations)); + Target->NumRelocations = NumRelocations; + return nullptr; } } diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index e867acf5bfd9..6115bb2d8c40 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -121,6 +121,8 @@ protected: // .o file. template class ObjectFile : public ELFFileBase { typedef ELFFileBase Base; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::SymRange Elf_Sym_Range; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index d4d854e9874b..83fb3aa601b7 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -56,6 +56,9 @@ InputSectionBase::InputSectionBase(elf::ObjectFile *File, !Config->GcSections || !(Flags & SHF_ALLOC)), File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info), Repl(this) { + NumRelocations = 0; + AreRelocsRela = false; + // The ELF spec states that a value of 0 means the section has // no alignment constraits. uint64_t V = std::max(Addralign, 1); @@ -466,12 +469,10 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { // we handle relocations directly here. auto *IS = dyn_cast>(this); if (IS && !(IS->Flags & SHF_ALLOC)) { - for (const Elf_Shdr *RelSec : IS->RelocSections) { - if (RelSec->sh_type == SHT_RELA) - IS->relocateNonAlloc(Buf, check(IS->getObj().relas(RelSec))); - else - IS->relocateNonAlloc(Buf, check(IS->getObj().rels(RelSec))); - } + if (IS->AreRelocsRela) + IS->relocateNonAlloc(Buf, IS->relas()); + else + IS->relocateNonAlloc(Buf, IS->rels()); return; } @@ -609,12 +610,11 @@ template void EhInputSection::split() { if (!this->Pieces.empty()) return; - if (RelocSection) { - ELFFile Obj = this->getObj(); - if (RelocSection->sh_type == SHT_RELA) - split(check(Obj.relas(RelocSection))); + if (this->NumRelocations) { + if (this->AreRelocsRela) + split(this->relas()); else - split(check(Obj.rels(RelocSection))); + split(this->rels()); return; } split(makeArrayRef(nullptr, nullptr)); diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index d6032af3a8b9..d39ee4c6189f 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -96,7 +96,10 @@ public: InputSectionBase() : InputSectionData(Regular, "", ArrayRef(), false, false), - Repl(this) {} + Repl(this) { + NumRelocations = 0; + AreRelocsRela = false; + } InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, StringRef Name, Kind SectionKind); @@ -106,6 +109,20 @@ public: Kind SectionKind); OutputSectionBase *OutSec = nullptr; + // Relocations that refer to this section. + const Elf_Rel *FirstRelocation = nullptr; + unsigned NumRelocations : 31; + unsigned AreRelocsRela : 1; + ArrayRef rels() const { + assert(!AreRelocsRela); + return llvm::makeArrayRef(FirstRelocation, NumRelocations); + } + ArrayRef relas() const { + assert(AreRelocsRela); + return llvm::makeArrayRef(static_cast(FirstRelocation), + NumRelocations); + } + // This pointer points to the "real" instance of this instance. // Usually Repl == this. However, if ICF merges two sections, // Repl pointer of one section points to another section. So, @@ -219,8 +236,6 @@ public: // rather than a single large blob of data. std::vector Pieces; - // Relocation section that refer to this one. - const Elf_Shdr *RelocSection = nullptr; }; // This corresponds to a non SHF_MERGE section of an input file. @@ -247,9 +262,6 @@ public: // beginning of the output section. void writeTo(uint8_t *Buf); - // Relocation sections that refer to this one. - llvm::TinyPtrVector RelocSections; - // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp index 60995a703338..8d129fc3ff13 100644 --- a/lld/ELF/MarkLive.cpp +++ b/lld/ELF/MarkLive.cpp @@ -80,15 +80,12 @@ static ResolvedReloc resolveReloc(InputSectionBase &Sec, template static void forEachSuccessor(InputSection &Sec, std::function)> Fn) { - ELFFile Obj = Sec.getFile()->getObj(); - for (const typename ELFT::Shdr *RelSec : Sec.RelocSections) { - if (RelSec->sh_type == SHT_RELA) { - for (const typename ELFT::Rela &Rel : check(Obj.relas(RelSec))) - Fn(resolveReloc(Sec, Rel)); - } else { - for (const typename ELFT::Rel &Rel : check(Obj.rels(RelSec))) - Fn(resolveReloc(Sec, Rel)); - } + if (Sec.AreRelocsRela) { + for (const typename ELFT::Rela &Rel : Sec.relas()) + Fn(resolveReloc(Sec, Rel)); + } else { + for (const typename ELFT::Rel &Rel : Sec.rels()) + Fn(resolveReloc(Sec, Rel)); } if (Sec.DependentSection) Fn({Sec.DependentSection, 0}); @@ -146,18 +143,17 @@ template static void scanEhFrameSection(EhInputSection &EH, std::function)> Enqueue) { - if (!EH.RelocSection) + if (!EH.NumRelocations) return; // Unfortunately we need to split .eh_frame early since some relocations in // .eh_frame keep other section alive and some don't. EH.split(); - ELFFile EObj = EH.getFile()->getObj(); - if (EH.RelocSection->sh_type == SHT_RELA) - scanEhFrameSection(EH, check(EObj.relas(EH.RelocSection)), Enqueue); + if (EH.AreRelocsRela) + scanEhFrameSection(EH, EH.relas(), Enqueue); else - scanEhFrameSection(EH, check(EObj.rels(EH.RelocSection)), Enqueue); + scanEhFrameSection(EH, EH.rels(), Enqueue); } // We do not garbage-collect two types of sections: diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 5402c3a40a5b..c2c37f20f75a 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -1162,12 +1162,11 @@ void EhOutputSection::addSection(InputSectionData *C) { if (Sec->Pieces.empty()) return; - if (const Elf_Shdr *RelSec = Sec->RelocSection) { - ELFFile Obj = Sec->getFile()->getObj(); - if (RelSec->sh_type == SHT_RELA) - addSectionAux(Sec, check(Obj.relas(RelSec))); + if (Sec->NumRelocations) { + if (Sec->AreRelocsRela) + addSectionAux(Sec, Sec->relas()); else - addSectionAux(Sec, check(Obj.rels(RelSec))); + addSectionAux(Sec, Sec->rels()); return; } addSectionAux(Sec, makeArrayRef(nullptr, nullptr)); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 190e303f31cb..07ba93022b60 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -787,14 +787,11 @@ static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { } } -template -void scanRelocations(InputSectionBase &S, - const typename ELFT::Shdr &RelSec) { - ELFFile EObj = S.getFile()->getObj(); - if (RelSec.sh_type == SHT_RELA) - scanRelocs(S, check(EObj.relas(&RelSec))); +template void scanRelocations(InputSectionBase &S) { + if (S.AreRelocsRela) + scanRelocs(S, S.relas()); else - scanRelocs(S, check(EObj.rels(&RelSec))); + scanRelocs(S, S.rels()); } template @@ -817,33 +814,22 @@ static void createThunks(InputSectionBase &C, ArrayRef Rels) { } } -template -void createThunks(InputSectionBase &S, - const typename ELFT::Shdr &RelSec) { - ELFFile EObj = S.getFile()->getObj(); - if (RelSec.sh_type == SHT_RELA) - createThunks(S, check(EObj.relas(&RelSec))); +template void createThunks(InputSectionBase &S) { + if (S.AreRelocsRela) + createThunks(S, S.relas()); else - createThunks(S, check(EObj.rels(&RelSec))); + createThunks(S, S.rels()); } -template void scanRelocations(InputSectionBase &, - const ELF32LE::Shdr &); -template void scanRelocations(InputSectionBase &, - const ELF32BE::Shdr &); -template void scanRelocations(InputSectionBase &, - const ELF64LE::Shdr &); -template void scanRelocations(InputSectionBase &, - const ELF64BE::Shdr &); +template void scanRelocations(InputSectionBase &); +template void scanRelocations(InputSectionBase &); +template void scanRelocations(InputSectionBase &); +template void scanRelocations(InputSectionBase &); -template void createThunks(InputSectionBase &, - const ELF32LE::Shdr &); -template void createThunks(InputSectionBase &, - const ELF32BE::Shdr &); -template void createThunks(InputSectionBase &, - const ELF64LE::Shdr &); -template void createThunks(InputSectionBase &, - const ELF64BE::Shdr &); +template void createThunks(InputSectionBase &); +template void createThunks(InputSectionBase &); +template void createThunks(InputSectionBase &); +template void createThunks(InputSectionBase &); template std::string getLocation(InputSectionBase &S, uint32_t Offset); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index f4b771b8bda8..d14b0a7ad952 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -81,11 +81,9 @@ struct Relocation { SymbolBody *Sym; }; -template -void scanRelocations(InputSectionBase &, const typename ELFT::Shdr &); +template void scanRelocations(InputSectionBase &); -template -void createThunks(InputSectionBase &, const typename ELFT::Shdr &); +template void createThunks(InputSectionBase &); template std::string getLocation(InputSectionBase &S, typename ELFT::uint Offset); diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 5a45a4a35a8a..3a6ead85d5ce 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -54,8 +54,7 @@ private: void addReservedSymbols(); void addInputSec(InputSectionBase *S); void createSections(); - void forEachRelSec(std::function &, - const typename ELFT::Shdr &)> Fn); + void forEachRelSec(std::function &)> Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); @@ -694,8 +693,7 @@ static void sortBySymbolsOrder(ArrayRef V) { template void Writer::forEachRelSec( - std::function &, const typename ELFT::Shdr &)> - Fn) { + std::function &)> Fn) { for (InputSectionBase *IS : Symtab::X->Sections) { if (!IS->Live) continue; @@ -706,14 +704,8 @@ void Writer::forEachRelSec( // processed by InputSection::relocateNonAlloc. if (!(IS->Flags & SHF_ALLOC)) continue; - if (auto *S = dyn_cast>(IS)) { - for (const Elf_Shdr *RelSec : S->RelocSections) - Fn(*S, *RelSec); - continue; - } - if (auto *S = dyn_cast>(IS)) - if (S->RelocSection) - Fn(*S, *S->RelocSection); + if (isa>(IS) || isa>(IS)) + Fn(*IS); } } diff --git a/lld/test/ELF/invalid/invalid-elf.test b/lld/test/ELF/invalid/invalid-elf.test index a20c4b4e7449..d49ab2f3cacf 100644 --- a/lld/test/ELF/invalid/invalid-elf.test +++ b/lld/test/ELF/invalid/invalid-elf.test @@ -26,6 +26,6 @@ # RUN: not ld.lld %p/Inputs/multiple-eh-relocs.elf -o %t2 2>&1 | \ # RUN: FileCheck --check-prefix=INVALID-EH-RELOCS %s -# INVALID-EH-RELOCS: multiple relocation sections to .eh_frame are not supported +# INVALID-EH-RELOCS: multiple relocation sections to one section are not supported .long foo