[lld] r276329 - Fix PR28575.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 21 13:18:31 PDT 2016
Author: rafael
Date: Thu Jul 21 15:18:30 2016
New Revision: 276329
URL: http://llvm.org/viewvc/llvm-project?rev=276329&view=rev
Log:
Fix PR28575.
Not all relocations from a .eh_frame that point to an executable
section should be ignored. In particular, the relocation finding the
personality function should not.
This is a reduction from trying to bootstrap a static lld on linux.
Added:
lld/trunk/test/ELF/eh-frame-gc2.s
Modified:
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/InputSection.h
lld/trunk/ELF/MarkLive.cpp
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/OutputSections.h
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Thu Jul 21 15:18:30 2016
@@ -443,14 +443,53 @@ bool EhInputSection<ELFT>::classof(const
return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
}
+// Returns the index of the first relocation that points to a region between
+// Begin and Begin+Size.
+template <class IntTy, class RelTy>
+static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels,
+ unsigned &RelocI) {
+ // Start search from RelocI for fast access. That works because the
+ // relocations are sorted in .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 <class ELFT>
void EhInputSection<ELFT>::split() {
+ // Early exit if already split.
+ if (!this->Pieces.empty())
+ return;
+
+ if (RelocSection) {
+ ELFFile<ELFT> &Obj = this->File->getObj();
+ if (RelocSection->sh_type == SHT_RELA)
+ split(Obj.relas(RelocSection));
+ else
+ split(Obj.rels(RelocSection));
+ return;
+ }
+ split(makeArrayRef<typename ELFT::Rela>(nullptr, nullptr));
+}
+
+template <class ELFT>
+template <class RelTy>
+void EhInputSection<ELFT>::split(ArrayRef<RelTy> Rels) {
ArrayRef<uint8_t> Data = this->getSectionData();
+ unsigned RelI = 0;
for (size_t Off = 0, End = Data.size(); Off != End;) {
size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
- this->Pieces.emplace_back(Off, Data.slice(Off, Size));
+ this->Pieces.emplace_back(Off, Data.slice(Off, Size),
+ getReloc(Off, Size, Rels, RelI));
// The empty record is the end marker.
if (Size == 4)
break;
Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Thu Jul 21 15:18:30 2016
@@ -149,6 +149,12 @@ private:
llvm::DenseSet<uintX_t> LiveOffsets;
};
+struct EhSectionPiece : public SectionPiece {
+ EhSectionPiece(size_t Off, ArrayRef<uint8_t> Data, unsigned FirstRelocation)
+ : SectionPiece(Off, Data), FirstRelocation(FirstRelocation) {}
+ unsigned FirstRelocation;
+};
+
// This corresponds to a .eh_frame section of an input file.
template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
public:
@@ -157,10 +163,11 @@ public:
EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
void split();
+ template <class RelTy> void split(ArrayRef<RelTy> Rels);
// Splittable sections are handled as a sequence of data
// rather than a single large blob of data.
- std::vector<SectionPiece> Pieces;
+ std::vector<EhSectionPiece> Pieces;
// Relocation section that refer to this one.
const Elf_Shdr *RelocSection = nullptr;
Modified: lld/trunk/ELF/MarkLive.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/MarkLive.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/MarkLive.cpp (original)
+++ lld/trunk/ELF/MarkLive.cpp Thu Jul 21 15:18:30 2016
@@ -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,70 @@ static void forEachSuccessor(InputSectio
run(Obj, Sec, RelSec, Fn);
}
+// The .eh_frame section is an unfortunate special case.
+// The section is divided in CIEs and FDEs and the relocations it can have are
+// * CIEs can refer to a personality function.
+// * FDEs can refer to a LSDA
+// * FDEs refer to the function they contain information about
+// The last kind of relocation cannot keep the referred section alive, or they
+// would keep everything alive in a common object file. In fact, each FDE is
+// alive if the section it refers to is alive.
+// To keep things simple, in here we just ignore the last relocation kind. The
+// other two keep the referred section alive.
+//
+// A possible improvement would be to fully process .eh_frame in the middle of
+// the gc pass. With that we would be able to also gc some sections holding
+// LSDAs and personality functions if we found that they were unused.
+template <class ELFT, class RelTy>
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH, ArrayRef<RelTy> Rels,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
+ const endianness E = ELFT::TargetEndianness;
+ for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) {
+ EhSectionPiece &Piece = EH.Pieces[I];
+ unsigned FirstRelI = Piece.FirstRelocation;
+ if (FirstRelI == (unsigned)-1)
+ continue;
+ if (read32<E>(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.
+ Enqueue(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 &Rel = Rels[I2];
+ if (Rel.r_offset >= PieceEnd)
+ break;
+ ResolvedReloc<ELFT> R = resolveReloc(EH, Rels[I2]);
+ if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
+ continue;
+ if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
+ continue;
+ Enqueue({R.Sec, 0});
+ }
+ }
+}
+
template <class ELFT>
-static void scanEhFrameSection(EhInputSection<ELFT> &EH,
- std::function<void(ResolvedReloc<ELFT>)> Fn) {
+static void
+scanEhFrameSection(EhInputSection<ELFT> &EH,
+ std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
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<ELFT> &EObj = EH.getFile()->getObj();
- run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
- if (!R.Sec || R.Sec == &InputSection<ELFT>::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), Enqueue);
+ else
+ scanEhFrameSection(EH, EObj.rels(EH.RelocSection), Enqueue);
}
// Sections listed below are special because they are used by the loader
Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Jul 21 15:18:30 2016
@@ -963,41 +963,22 @@ template <class ELFT>
EhOutputSection<ELFT>::EhOutputSection()
: OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
-// Returns the first relocation that points to a region
-// between Begin and Begin+Size.
-template <class IntTy, class RelTy>
-static const RelTy *getReloc(IntTy Begin, IntTy Size, ArrayRef<RelTy> &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<RelTy>();
- 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 <class ELFT>
template <class RelTy>
-CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
+CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels) {
+ ArrayRef<RelTy> Rels) {
const endianness E = ELFT::TargetEndianness;
if (read32<E>(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);
+ unsigned FirstRelI = Piece.FirstRelocation;
+ 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 +995,14 @@ CieRecord *EhOutputSection<ELFT>::addCie
// points to a live function.
template <class ELFT>
template <class RelTy>
-bool EhOutputSection<ELFT>::isFdeLive(SectionPiece &Piece,
+bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels) {
- const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels);
- if (!Rel)
+ ArrayRef<RelTy> Rels) {
+ unsigned FirstRelI = Piece.FirstRelocation;
+ 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<DefinedRegular<ELFT>>(&B);
if (!D || !D->Section)
return false;
@@ -1039,7 +1021,7 @@ void EhOutputSection<ELFT>::addSectionAu
const endianness E = ELFT::TargetEndianness;
DenseMap<size_t, CieRecord *> OffsetToCie;
- for (SectionPiece &Piece : Sec->Pieces) {
+ for (EhSectionPiece &Piece : Sec->Pieces) {
// The empty record is the end marker.
if (Piece.size() == 4)
return;
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=276329&r1=276328&r2=276329&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Thu Jul 21 15:18:30 2016
@@ -24,7 +24,7 @@ namespace lld {
namespace elf {
class SymbolBody;
-struct SectionPiece;
+struct EhSectionPiece;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
@@ -372,8 +372,8 @@ private:
};
struct CieRecord {
- SectionPiece *Piece = nullptr;
- std::vector<SectionPiece *> FdePieces;
+ EhSectionPiece *Piece = nullptr;
+ std::vector<EhSectionPiece *> FdePieces;
};
// Output section for .eh_frame.
@@ -399,12 +399,12 @@ private:
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
template <class RelTy>
- CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels);
+ CieRecord *addCie(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> Rels);
template <class RelTy>
- bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
- ArrayRef<RelTy> &Rels);
+ bool isFdeLive(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
+ ArrayRef<RelTy> Rels);
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
Added: lld/trunk/test/ELF/eh-frame-gc2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-gc2.s?rev=276329&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-gc2.s (added)
+++ lld/trunk/test/ELF/eh-frame-gc2.s Thu Jul 21 15:18:30 2016
@@ -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:
More information about the llvm-commits
mailing list