Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -172,6 +172,7 @@ EhInputSection(ObjectFile *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase *S); void split(); + template void split(ArrayRef Rels); // Translate an offset in the input section to an offset in the output // section. @@ -179,6 +180,8 @@ // Relocation section that refer to this one. const Elf_Shdr *RelocSection = nullptr; + + std::vector FirstRelocOfPiece; }; // This corresponds to a non SHF_MERGE section of an input file. Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -451,14 +451,56 @@ return S->SectionKind == InputSectionBase::EHFrame; } +// Returns the index of the first relocation that points to a region between +// Begin and Begin+Size. +template +static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef &Rels, + unsigned &RelocI) { + // Start search from RelocI for fast access. That means we expect that the + // relocations are sorted and we are looking up symbols in sequential order. + // It is naturally satisfied for .eh_frame. + for (unsigned N = Rels.size(); RelocI < N; ++RelocI) { + const RelTy &Rel = Rels[RelocI]; + if (Rel.r_offset < Begin) + continue; + + if (Rel.r_offset < Begin + Size) + return RelocI; + return -1; + } + return -1; +} + // .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() { + // Early exit if already split. + if (!this->Pieces.empty()) + return; + + if (RelocSection) { + ELFFile &Obj = this->File->getObj(); + if (RelocSection->sh_type == SHT_RELA) + split(Obj.relas(RelocSection)); + else + split(Obj.rels(RelocSection)); + return; + } + split(makeArrayRef(nullptr, nullptr)); +} + +template +template +void EhInputSection::split(ArrayRef Rels) { ArrayRef Data = this->getSectionData(); + unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { size_t Size = readEhRecordSize(Data.slice(Off)); this->Pieces.emplace_back(Off, Data.slice(Off, Size)); + SectionPiece &Piece = this->Pieces.back(); + FirstRelocOfPiece.push_back( + getReloc(Piece.InputOff, Piece.size(), Rels, RelI)); // The empty record is the end marker. if (Size == 4) break; Index: ELF/MarkLive.cpp =================================================================== --- ELF/MarkLive.cpp +++ ELF/MarkLive.cpp @@ -36,6 +36,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; @@ -95,19 +96,54 @@ run(Obj, Sec, RelSec, Fn); } +template +static void scanEhFrameSection(EhInputSection &EH, ArrayRef Rels, + std::function)> Fn) { + const endianness E = ELFT::TargetEndianness; + for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) { + unsigned FirstRelI = EH.FirstRelocOfPiece[I]; + if (FirstRelI == (unsigned)-1) + continue; + SectionPiece &Piece = EH.Pieces[I]; + if (read32(Piece.data().data() + 4) == 0) { + // This is a CIE, we only need to worry about the first relocation. It is + // known to point to the personality function. + Fn(resolveReloc(EH, Rels[FirstRelI])); + continue; + } + // This is a FDE. The relocations point to the described function or to + // a LSDA. We only need to keep the LSDA alive, so ignore anything that + // points to executable sections. + typename ELFT::uint PieceEnd = Piece.InputOff + Piece.size(); + for (unsigned I2 = FirstRelI, N2 = Rels.size(); I2 < N2; ++I2) { + const RelTy &RI = Rels[I2]; + if (RI.r_offset >= PieceEnd) + break; + ResolvedReloc R = resolveReloc(EH, Rels[I2]); + if (!R.Sec || R.Sec == &InputSection::Discarded) + continue; + if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR) + continue; + Fn({R.Sec, 0}); + } + } +} + template static void scanEhFrameSection(EhInputSection &EH, std::function)> Fn) { if (!EH.RelocSection) 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(); - run(EObj, EH, EH.RelocSection, [&](ResolvedReloc R) { - if (!R.Sec || R.Sec == &InputSection::Discarded) - return; - if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR) - return; - Fn({R.Sec, 0}); - }); + if (EH.RelocSection->sh_type == SHT_RELA) + scanEhFrameSection(EH, EObj.relas(EH.RelocSection), Fn); + else + scanEhFrameSection(EH, EObj.rels(EH.RelocSection), Fn); } // Sections listed below are special because they are used by the loader Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -399,12 +399,12 @@ void addSectionAux(EhInputSection *S, llvm::ArrayRef Rels); template - CieRecord *addCie(SectionPiece &Piece, EhInputSection *Sec, - ArrayRef &Rels); + CieRecord *addCie(SectionPiece &Piece, unsigned FirstRelI, + EhInputSection *Sec, ArrayRef Rels); template - bool isFdeLive(SectionPiece &Piece, EhInputSection *Sec, - ArrayRef &Rels); + bool isFdeLive(SectionPiece &Piece, unsigned FirstRelI, + EhInputSection *Sec, ArrayRef Rels); uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -963,41 +963,21 @@ EhOutputSection::EhOutputSection() : OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {} -// Returns the first relocation that points to a region -// between Begin and Begin+Size. -template -static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef &Rels) { - for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) { - if (I->r_offset < Begin) - continue; - - // Truncate Rels for fast access. That means we expect that the - // relocations are sorted and we are looking up symbols in - // sequential order. It is naturally satisfied for .eh_frame. - Rels = Rels.slice(I - Rels.begin()); - if (I->r_offset < Begin + Size) - return I; - return nullptr; - } - Rels = ArrayRef(); - return nullptr; -} - // Search for an existing CIE record or create a new one. // CIE records from input object files are uniquified by their contents // and where their relocations point to. template template -CieRecord *EhOutputSection::addCie(SectionPiece &Piece, - EhInputSection *Sec, - ArrayRef &Rels) { +CieRecord * +EhOutputSection::addCie(SectionPiece &Piece, unsigned FirstRelI, + EhInputSection *Sec, ArrayRef Rels) { const endianness E = ELFT::TargetEndianness; if (read32(Piece.data().data() + 4) != 0) fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName()); SymbolBody *Personality = nullptr; - if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels)) - Personality = &Sec->getFile()->getRelocTargetSym(*Rel); + if (FirstRelI != (unsigned)-1) + Personality = &Sec->getFile()->getRelocTargetSym(Rels[FirstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. CieRecord *Cie = &CieMap[{Piece.data(), Personality}]; @@ -1014,13 +994,13 @@ // points to a live function. template template -bool EhOutputSection::isFdeLive(SectionPiece &Piece, +bool EhOutputSection::isFdeLive(SectionPiece &Piece, unsigned FirstRelI, EhInputSection *Sec, - ArrayRef &Rels) { - const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels); - if (!Rel) + ArrayRef Rels) { + if (FirstRelI == (unsigned)-1) fatal("FDE doesn't reference another section"); - SymbolBody &B = Sec->getFile()->getRelocTargetSym(*Rel); + const RelTy &Rel = Rels[FirstRelI]; + SymbolBody &B = Sec->getFile()->getRelocTargetSym(Rel); auto *D = dyn_cast>(&B); if (!D || !D->Section) return false; @@ -1039,7 +1019,9 @@ const endianness E = ELFT::TargetEndianness; DenseMap OffsetToCie; - for (SectionPiece &Piece : Sec->Pieces) { + for (unsigned I = 0, N = Sec->Pieces.size(); I < N; ++I) { + SectionPiece &Piece = Sec->Pieces[I]; + unsigned FirstRelI = Sec->FirstRelocOfPiece[I]; // The empty record is the end marker. if (Piece.size() == 4) return; @@ -1047,7 +1029,7 @@ size_t Offset = Piece.InputOff; uint32_t ID = read32(Piece.data().data() + 4); if (ID == 0) { - OffsetToCie[Offset] = addCie(Piece, Sec, Rels); + OffsetToCie[Offset] = addCie(Piece, FirstRelI, Sec, Rels); continue; } @@ -1056,7 +1038,7 @@ if (!Cie) fatal("invalid CIE reference"); - if (!isFdeLive(Piece, Sec, Rels)) + if (!isFdeLive(Piece, FirstRelI, Sec, Rels)) continue; Cie->FdePieces.push_back(&Piece); NumFdes++; Index: test/ELF/eh-frame-gc2.s =================================================================== --- /dev/null +++ test/ELF/eh-frame-gc2.s @@ -0,0 +1,15 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o +// RUN: ld.lld --gc-sections %t.o -o %t +// RUN: llvm-readobj -s %t | FileCheck %s + +// Test that the we don't gc the personality function. +// CHECK: Name: .foobar + + .globl _start +_start: + .cfi_startproc + .cfi_personality 3, foobar + .cfi_endproc + .section .foobar,"ax" +foobar: