Skip scanRelocs for non-alloc sections.

Relocations against sections with no SHF_ALLOC bit are R_ABS relocations.
Currently we are creating Relocations vector for them, but that is wasteful.
This patch is to skip vector construction and to directly apply relocations
in place.

This patch seems to be pretty effective for large executables with debug info.
r266158 (Rafael's patch to change the way how we apply relocations) caused a
temporary performance degradation for such executables, but this patch makes
it even faster than before.

Time to link clang with debug info (output size is 1070 MB):

  before r266158: 15.312 seconds (0%)
  r266158:        17.301 seconds (+13.0%)
  Head:           16.484 seconds (+7.7%)
  w/patch:        13.166 seconds (-14.0%)

Differential Revision: http://reviews.llvm.org/D19645

llvm-svn: 267917
This commit is contained in:
Rui Ueyama 2016-04-28 18:42:04 +00:00
parent c5fce69031
commit 2b6fb80384
4 changed files with 56 additions and 20 deletions

View File

@ -226,8 +226,50 @@ getSymVA(uint32_t Type, typename ELFT::uint A, typename ELFT::uint P,
llvm_unreachable("Invalid expression");
}
// This function applies relocations to sections without SHF_ALLOC bit.
// Such sections are never mapped to memory at runtime. Debug sections are
// an example. Relocations in non-alloc sections are much easier to
// handle than in allocated sections because it will never need complex
// treatement such as GOT or PLT (because at runtime no one refers them).
// So, we handle relocations for non-alloc sections directly in this
// function as a performance optimization.
template <class ELFT>
template <class RelTy>
void InputSection<ELFT>::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) {
const unsigned Bits = sizeof(uintX_t) * 8;
for (const RelTy &Rel : Rels) {
uint8_t *BufLoc = Buf + Rel.r_offset;
uintX_t AddrLoc = this->OutSec->getVA() + Rel.r_offset;
uint32_t Type = Rel.getType(Config->Mips64EL);
SymbolBody &Sym = this->File->getRelocTargetSym(Rel);
if (Target->getRelExpr(Type, Sym) != R_ABS) {
error(this->getSectionName() + " has non-ABS reloc");
return;
}
uint64_t SymVA = SignExtend64<Bits>(getSymVA<ELFT>(
Type, getAddend<ELFT>(Rel), AddrLoc, Sym, BufLoc, *this->File, R_ABS));
Target->relocateOne(BufLoc, Type, SymVA);
}
}
template <class ELFT>
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
// scanReloc function in Writer.cpp constructs Relocations
// vector only for SHF_ALLOC'ed sections. For other sections,
// we handle relocations directly here.
auto *IS = dyn_cast<InputSection<ELFT>>(this);
if (IS && !(IS->Header->sh_flags & SHF_ALLOC)) {
for (const Elf_Shdr *RelSec : IS->RelocSections) {
if (RelSec->sh_type == SHT_RELA)
IS->relocateNonAlloc(Buf, IS->File->getObj().relas(RelSec));
else
IS->relocateNonAlloc(Buf, IS->File->getObj().rels(RelSec));
}
return;
}
const unsigned Bits = sizeof(uintX_t) * 8;
for (const Relocation &Rel : Relocations) {
uintX_t Offset = Rel.Offset;

View File

@ -218,6 +218,9 @@ public:
// Size of chunk with thunks code.
uint64_t getThunksSize() const;
template <class RelTy>
void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
private:
template <class RelTy>
void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);

View File

@ -532,12 +532,10 @@ template <class ELFT>
template <class RelTy>
void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
uintX_t Flags = C.getSectionHdr()->sh_flags;
bool IsAlloc = Flags & SHF_ALLOC;
bool IsWrite = Flags & SHF_WRITE;
auto AddDyn = [=](const DynamicReloc<ELFT> &Reloc) {
if (IsAlloc)
Out<ELFT>::RelaDyn->addReloc(Reloc);
Out<ELFT>::RelaDyn->addReloc(Reloc);
};
const elf::ObjectFile<ELFT> &File = *C.getFile();
@ -593,7 +591,7 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// in a read-only section, we need to create a copy relocation for the
// symbol.
if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
if (IsAlloc && !IsWrite && needsCopyRel(Expr, *B)) {
if (!IsWrite && needsCopyRel(Expr, *B)) {
if (!B->needsCopy())
addCopyRelSymbol(B);
C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
@ -630,10 +628,9 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
if (IsAlloc)
Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
Body.getGotPltOffset<ELFT>(),
!Preemptible, &Body, 0});
Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
Body.getGotPltOffset<ELFT>(),
!Preemptible, &Body, 0});
} else {
if (Body.isInGot())
continue;
@ -744,17 +741,11 @@ template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
// Scan all relocations. Each relocation goes through a series
// of tests to determine if it needs special treatment, such as
// creating GOT, PLT, copy relocations, etc.
//
// The current code is a bit wasteful because it scans relocations
// in non-SHF_ALLOC sections. Such sections are never mapped to
// memory at runtime. Debug section is an example. Relocations in
// non-alloc sections are much easier to handle because it will
// never need complex treatement such as GOT or PLT (because at
// runtime no one refers them). We probably should skip non-alloc
// sections here and directly handle non-alloc relocations in
// writeTo function.
for (const Elf_Shdr *RelSec : C.RelocSections)
scanRelocs(C, *RelSec);
// Note that relocations for non-alloc sections are directly
// processed by InputSection::relocateNative.
if (C.getSectionHdr()->sh_flags & SHF_ALLOC)
for (const Elf_Shdr *RelSec : C.RelocSections)
scanRelocs(C, *RelSec);
}
template <class ELFT>

View File

@ -33,7 +33,7 @@
// CHECK-NEXT: AddressAlignment: 1
// CHECK-NEXT: EntrySize: 0
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 00100000 00000000 00000000 00000000
// CHECK-NEXT: 0000: 00100000 00000000 00100000 00000000
// CHECK-NEXT: )
// CHECK: Relocations [