forked from OSchip/llvm-project
				
			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. llvm-svn: 276329
This commit is contained in:
		
							parent
							
								
									9eec550a2b
								
							
						
					
					
						commit
						2deeb6093d
					
				| 
						 | 
					@ -443,14 +443,53 @@ bool EhInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
 | 
				
			||||||
  return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
 | 
					  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.
 | 
					// .eh_frame is a sequence of CIE or FDE records.
 | 
				
			||||||
// This function splits an input section into records and returns them.
 | 
					// This function splits an input section into records and returns them.
 | 
				
			||||||
template <class ELFT>
 | 
					template <class ELFT>
 | 
				
			||||||
void EhInputSection<ELFT>::split() {
 | 
					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();
 | 
					  ArrayRef<uint8_t> Data = this->getSectionData();
 | 
				
			||||||
 | 
					  unsigned RelI = 0;
 | 
				
			||||||
  for (size_t Off = 0, End = Data.size(); Off != End;) {
 | 
					  for (size_t Off = 0, End = Data.size(); Off != End;) {
 | 
				
			||||||
    size_t Size = readEhRecordSize<ELFT>(Data.slice(Off));
 | 
					    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.
 | 
					    // The empty record is the end marker.
 | 
				
			||||||
    if (Size == 4)
 | 
					    if (Size == 4)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,6 +149,12 @@ private:
 | 
				
			||||||
  llvm::DenseSet<uintX_t> LiveOffsets;
 | 
					  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.
 | 
					// This corresponds to a .eh_frame section of an input file.
 | 
				
			||||||
template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
 | 
					template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
| 
						 | 
					@ -157,10 +163,11 @@ public:
 | 
				
			||||||
  EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
 | 
					  EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
 | 
				
			||||||
  static bool classof(const InputSectionBase<ELFT> *S);
 | 
					  static bool classof(const InputSectionBase<ELFT> *S);
 | 
				
			||||||
  void split();
 | 
					  void split();
 | 
				
			||||||
 | 
					  template <class RelTy> void split(ArrayRef<RelTy> Rels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Splittable sections are handled as a sequence of data
 | 
					  // Splittable sections are handled as a sequence of data
 | 
				
			||||||
  // rather than a single large blob 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.
 | 
					  // Relocation section that refer to this one.
 | 
				
			||||||
  const Elf_Shdr *RelocSection = nullptr;
 | 
					  const Elf_Shdr *RelocSection = nullptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@
 | 
				
			||||||
using namespace llvm;
 | 
					using namespace llvm;
 | 
				
			||||||
using namespace llvm::ELF;
 | 
					using namespace llvm::ELF;
 | 
				
			||||||
using namespace llvm::object;
 | 
					using namespace llvm::object;
 | 
				
			||||||
 | 
					using namespace llvm::support::endian;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace lld;
 | 
					using namespace lld;
 | 
				
			||||||
using namespace lld::elf;
 | 
					using namespace lld::elf;
 | 
				
			||||||
| 
						 | 
					@ -95,19 +96,70 @@ static void forEachSuccessor(InputSection<ELFT> &Sec,
 | 
				
			||||||
    run(Obj, Sec, RelSec, Fn);
 | 
					    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>
 | 
					template <class ELFT>
 | 
				
			||||||
static void scanEhFrameSection(EhInputSection<ELFT> &EH,
 | 
					static void
 | 
				
			||||||
                               std::function<void(ResolvedReloc<ELFT>)> Fn) {
 | 
					scanEhFrameSection(EhInputSection<ELFT> &EH,
 | 
				
			||||||
 | 
					                   std::function<void(ResolvedReloc<ELFT>)> Enqueue) {
 | 
				
			||||||
  if (!EH.RelocSection)
 | 
					  if (!EH.RelocSection)
 | 
				
			||||||
    return;
 | 
					    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();
 | 
					  ELFFile<ELFT> &EObj = EH.getFile()->getObj();
 | 
				
			||||||
  run<ELFT>(EObj, EH, EH.RelocSection, [&](ResolvedReloc<ELFT> R) {
 | 
					  if (EH.RelocSection->sh_type == SHT_RELA)
 | 
				
			||||||
    if (!R.Sec || R.Sec == &InputSection<ELFT>::Discarded)
 | 
					    scanEhFrameSection(EH, EObj.relas(EH.RelocSection), Enqueue);
 | 
				
			||||||
      return;
 | 
					  else
 | 
				
			||||||
    if (R.Sec->getSectionHdr()->sh_flags & SHF_EXECINSTR)
 | 
					    scanEhFrameSection(EH, EObj.rels(EH.RelocSection), Enqueue);
 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    Fn({R.Sec, 0});
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sections listed below are special because they are used by the loader
 | 
					// Sections listed below are special because they are used by the loader
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -963,41 +963,22 @@ template <class ELFT>
 | 
				
			||||||
EhOutputSection<ELFT>::EhOutputSection()
 | 
					EhOutputSection<ELFT>::EhOutputSection()
 | 
				
			||||||
    : OutputSectionBase<ELFT>(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
 | 
					    : 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.
 | 
					// Search for an existing CIE record or create a new one.
 | 
				
			||||||
// CIE records from input object files are uniquified by their contents
 | 
					// CIE records from input object files are uniquified by their contents
 | 
				
			||||||
// and where their relocations point to.
 | 
					// and where their relocations point to.
 | 
				
			||||||
template <class ELFT>
 | 
					template <class ELFT>
 | 
				
			||||||
template <class RelTy>
 | 
					template <class RelTy>
 | 
				
			||||||
CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
 | 
					CieRecord *EhOutputSection<ELFT>::addCie(EhSectionPiece &Piece,
 | 
				
			||||||
                                         EhInputSection<ELFT> *Sec,
 | 
					                                         EhInputSection<ELFT> *Sec,
 | 
				
			||||||
                                         ArrayRef<RelTy> &Rels) {
 | 
					                                         ArrayRef<RelTy> Rels) {
 | 
				
			||||||
  const endianness E = ELFT::TargetEndianness;
 | 
					  const endianness E = ELFT::TargetEndianness;
 | 
				
			||||||
  if (read32<E>(Piece.data().data() + 4) != 0)
 | 
					  if (read32<E>(Piece.data().data() + 4) != 0)
 | 
				
			||||||
    fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
 | 
					    fatal("CIE expected at beginning of .eh_frame: " + Sec->getSectionName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SymbolBody *Personality = nullptr;
 | 
					  SymbolBody *Personality = nullptr;
 | 
				
			||||||
  if (const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels))
 | 
					  unsigned FirstRelI = Piece.FirstRelocation;
 | 
				
			||||||
    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.
 | 
					  // Search for an existing CIE by CIE contents/relocation target pair.
 | 
				
			||||||
  CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
 | 
					  CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
 | 
				
			||||||
| 
						 | 
					@ -1014,13 +995,14 @@ CieRecord *EhOutputSection<ELFT>::addCie(SectionPiece &Piece,
 | 
				
			||||||
// points to a live function.
 | 
					// points to a live function.
 | 
				
			||||||
template <class ELFT>
 | 
					template <class ELFT>
 | 
				
			||||||
template <class RelTy>
 | 
					template <class RelTy>
 | 
				
			||||||
bool EhOutputSection<ELFT>::isFdeLive(SectionPiece &Piece,
 | 
					bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
 | 
				
			||||||
                                      EhInputSection<ELFT> *Sec,
 | 
					                                      EhInputSection<ELFT> *Sec,
 | 
				
			||||||
                                      ArrayRef<RelTy> &Rels) {
 | 
					                                      ArrayRef<RelTy> Rels) {
 | 
				
			||||||
  const RelTy *Rel = getReloc(Piece.InputOff, Piece.size(), Rels);
 | 
					  unsigned FirstRelI = Piece.FirstRelocation;
 | 
				
			||||||
  if (!Rel)
 | 
					  if (FirstRelI == (unsigned)-1)
 | 
				
			||||||
    fatal("FDE doesn't reference another section");
 | 
					    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);
 | 
					  auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
 | 
				
			||||||
  if (!D || !D->Section)
 | 
					  if (!D || !D->Section)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
| 
						 | 
					@ -1039,7 +1021,7 @@ void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
 | 
				
			||||||
  const endianness E = ELFT::TargetEndianness;
 | 
					  const endianness E = ELFT::TargetEndianness;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DenseMap<size_t, CieRecord *> OffsetToCie;
 | 
					  DenseMap<size_t, CieRecord *> OffsetToCie;
 | 
				
			||||||
  for (SectionPiece &Piece : Sec->Pieces) {
 | 
					  for (EhSectionPiece &Piece : Sec->Pieces) {
 | 
				
			||||||
    // The empty record is the end marker.
 | 
					    // The empty record is the end marker.
 | 
				
			||||||
    if (Piece.size() == 4)
 | 
					    if (Piece.size() == 4)
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ namespace lld {
 | 
				
			||||||
namespace elf {
 | 
					namespace elf {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SymbolBody;
 | 
					class SymbolBody;
 | 
				
			||||||
struct SectionPiece;
 | 
					struct EhSectionPiece;
 | 
				
			||||||
template <class ELFT> class SymbolTable;
 | 
					template <class ELFT> class SymbolTable;
 | 
				
			||||||
template <class ELFT> class SymbolTableSection;
 | 
					template <class ELFT> class SymbolTableSection;
 | 
				
			||||||
template <class ELFT> class StringTableSection;
 | 
					template <class ELFT> class StringTableSection;
 | 
				
			||||||
| 
						 | 
					@ -372,8 +372,8 @@ private:
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct CieRecord {
 | 
					struct CieRecord {
 | 
				
			||||||
  SectionPiece *Piece = nullptr;
 | 
					  EhSectionPiece *Piece = nullptr;
 | 
				
			||||||
  std::vector<SectionPiece *> FdePieces;
 | 
					  std::vector<EhSectionPiece *> FdePieces;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Output section for .eh_frame.
 | 
					// Output section for .eh_frame.
 | 
				
			||||||
| 
						 | 
					@ -399,12 +399,12 @@ private:
 | 
				
			||||||
  void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
 | 
					  void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <class RelTy>
 | 
					  template <class RelTy>
 | 
				
			||||||
  CieRecord *addCie(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
 | 
					  CieRecord *addCie(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
 | 
				
			||||||
                    ArrayRef<RelTy> &Rels);
 | 
					                    ArrayRef<RelTy> Rels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <class RelTy>
 | 
					  template <class RelTy>
 | 
				
			||||||
  bool isFdeLive(SectionPiece &Piece, EhInputSection<ELFT> *Sec,
 | 
					  bool isFdeLive(EhSectionPiece &Piece, EhInputSection<ELFT> *Sec,
 | 
				
			||||||
                 ArrayRef<RelTy> &Rels);
 | 
					                 ArrayRef<RelTy> Rels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
 | 
					  uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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:
 | 
				
			||||||
		Loading…
	
		Reference in New Issue