forked from OSchip/llvm-project
[ELF] Convert EhFrameHeader to input section
Differential revision: https://reviews.llvm.org/D26906 llvm-svn: 287549
This commit is contained in:
parent
94ddbb4a04
commit
952eb4d348
|
@ -67,46 +67,6 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) {
|
|||
// plus one. Note that we don't support multiple versions yet.
|
||||
static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; }
|
||||
|
||||
template <class ELFT>
|
||||
EhFrameHeader<ELFT>::EhFrameHeader()
|
||||
: OutputSectionBase(".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC) {}
|
||||
|
||||
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
|
||||
// Each entry of the search table consists of two values,
|
||||
// the starting PC from where FDEs covers, and the FDE's address.
|
||||
// It is sorted by PC.
|
||||
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
|
||||
// Sort the FDE list by their PC and uniqueify. Usually there is only
|
||||
// one FDE for a PC (i.e. function), but if ICF merges two functions
|
||||
// into one, there can be more than one FDEs pointing to the address.
|
||||
auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
|
||||
std::stable_sort(Fdes.begin(), Fdes.end(), Less);
|
||||
auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
|
||||
Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
|
||||
|
||||
Buf[0] = 1;
|
||||
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
||||
Buf[2] = DW_EH_PE_udata4;
|
||||
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
|
||||
write32<E>(Buf + 4, Out<ELFT>::EhFrame->Addr - this->Addr - 4);
|
||||
write32<E>(Buf + 8, Fdes.size());
|
||||
Buf += 12;
|
||||
|
||||
uintX_t VA = this->Addr;
|
||||
for (FdeData &Fde : Fdes) {
|
||||
write32<E>(Buf, Fde.Pc - VA);
|
||||
write32<E>(Buf + 4, Fde.FdeVA - VA);
|
||||
Buf += 8;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void EhFrameHeader<ELFT>::finalize() {
|
||||
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
|
||||
this->Size = 12 + Out<ELFT>::EhFrame->NumFdes * 8;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
|
||||
Fdes.push_back({Pc, FdeVA});
|
||||
|
@ -500,13 +460,13 @@ template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
// Construct .eh_frame_hdr. .eh_frame_hdr is a binary search table
|
||||
// to get a FDE from an address to which FDE is applied. So here
|
||||
// we obtain two addresses and pass them to EhFrameHdr object.
|
||||
if (Out<ELFT>::EhFrameHdr) {
|
||||
if (In<ELFT>::EhFrameHdr) {
|
||||
for (CieRecord *Cie : Cies) {
|
||||
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece->data());
|
||||
for (SectionPiece *Fde : Cie->FdePieces) {
|
||||
uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
|
||||
uintX_t FdeVA = this->Addr + Fde->OutputOff;
|
||||
Out<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
|
||||
In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -828,11 +788,6 @@ template void OutputSectionBase::writeHeaderTo<ELF32BE>(ELF32BE::Shdr *Shdr);
|
|||
template void OutputSectionBase::writeHeaderTo<ELF64LE>(ELF64LE::Shdr *Shdr);
|
||||
template void OutputSectionBase::writeHeaderTo<ELF64BE>(ELF64BE::Shdr *Shdr);
|
||||
|
||||
template class EhFrameHeader<ELF32LE>;
|
||||
template class EhFrameHeader<ELF32BE>;
|
||||
template class EhFrameHeader<ELF64LE>;
|
||||
template class EhFrameHeader<ELF64BE>;
|
||||
|
||||
template class OutputSection<ELF32LE>;
|
||||
template class OutputSection<ELF32BE>;
|
||||
template class OutputSection<ELF64LE>;
|
||||
|
|
|
@ -42,7 +42,6 @@ public:
|
|||
enum Kind {
|
||||
Base,
|
||||
EHFrame,
|
||||
EHFrameHdr,
|
||||
Merge,
|
||||
Regular,
|
||||
VersDef,
|
||||
|
@ -272,37 +271,6 @@ private:
|
|||
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
|
||||
};
|
||||
|
||||
// --eh-frame-hdr option tells linker to construct a header for all the
|
||||
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
|
||||
// and also to a PT_GNU_EH_FRAME segment.
|
||||
// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
|
||||
// calling dl_iterate_phdr.
|
||||
// This section contains a lookup table for quick binary search of FDEs.
|
||||
// Detailed info about internals can be found in Ian Lance Taylor's blog:
|
||||
// http://www.airs.com/blog/archives/460 (".eh_frame")
|
||||
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
|
||||
template <class ELFT> class EhFrameHeader final : public OutputSectionBase {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
EhFrameHeader();
|
||||
void finalize() override;
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void addFde(uint32_t Pc, uint32_t FdeVA);
|
||||
Kind getKind() const override { return EHFrameHdr; }
|
||||
static bool classof(const OutputSectionBase *B) {
|
||||
return B->getKind() == EHFrameHdr;
|
||||
}
|
||||
|
||||
private:
|
||||
struct FdeData {
|
||||
uint32_t Pc;
|
||||
uint32_t FdeVA;
|
||||
};
|
||||
|
||||
std::vector<FdeData> Fdes;
|
||||
};
|
||||
|
||||
// All output sections that are hadnled by the linker specially are
|
||||
// globally accessible. Writer initializes them, so don't use them
|
||||
// until Writer is initialized.
|
||||
|
@ -311,7 +279,6 @@ template <class ELFT> struct Out {
|
|||
typedef typename ELFT::Phdr Elf_Phdr;
|
||||
|
||||
static uint8_t First;
|
||||
static EhFrameHeader<ELFT> *EhFrameHdr;
|
||||
static EhOutputSection<ELFT> *EhFrame;
|
||||
static OutputSection<ELFT> *Bss;
|
||||
static OutputSection<ELFT> *MipsRldMap;
|
||||
|
@ -363,7 +330,6 @@ template <class ELFT> uint64_t getHeaderSize() {
|
|||
}
|
||||
|
||||
template <class ELFT> uint8_t Out<ELFT>::First;
|
||||
template <class ELFT> EhFrameHeader<ELFT> *Out<ELFT>::EhFrameHdr;
|
||||
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::MipsRldMap;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "lld/Config/Version.h"
|
||||
#include "lld/Core/Parallel.h"
|
||||
#include "llvm/Support/Dwarf.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/MD5.h"
|
||||
#include "llvm/Support/RandomNumberGenerator.h"
|
||||
|
@ -35,6 +36,7 @@
|
|||
#include <cstdlib>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dwarf;
|
||||
using namespace llvm::ELF;
|
||||
using namespace llvm::object;
|
||||
using namespace llvm::support;
|
||||
|
@ -1403,6 +1405,46 @@ template <class ELFT> void GdbIndexSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
EhFrameHeader<ELFT>::EhFrameHeader()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {}
|
||||
|
||||
// .eh_frame_hdr contains a binary search table of pointers to FDEs.
|
||||
// Each entry of the search table consists of two values,
|
||||
// the starting PC from where FDEs covers, and the FDE's address.
|
||||
// It is sorted by PC.
|
||||
template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
|
||||
// Sort the FDE list by their PC and uniqueify. Usually there is only
|
||||
// one FDE for a PC (i.e. function), but if ICF merges two functions
|
||||
// into one, there can be more than one FDEs pointing to the address.
|
||||
auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
|
||||
std::stable_sort(Fdes.begin(), Fdes.end(), Less);
|
||||
auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
|
||||
Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
|
||||
|
||||
Buf[0] = 1;
|
||||
Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
||||
Buf[2] = DW_EH_PE_udata4;
|
||||
Buf[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4;
|
||||
write32<E>(Buf + 4, Out<ELFT>::EhFrame->Addr - this->getVA() - 4);
|
||||
write32<E>(Buf + 8, Fdes.size());
|
||||
Buf += 12;
|
||||
|
||||
uintX_t VA = this->getVA();
|
||||
for (FdeData &Fde : Fdes) {
|
||||
write32<E>(Buf, Fde.Pc - VA);
|
||||
write32<E>(Buf + 4, Fde.FdeVA - VA);
|
||||
Buf += 8;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> size_t EhFrameHeader<ELFT>::getSize() const {
|
||||
// .eh_frame_hdr has a 12 bytes header followed by an array of FDEs.
|
||||
return 12 + Out<ELFT>::EhFrame->NumFdes * 8;
|
||||
}
|
||||
|
||||
template InputSection<ELF32LE> *elf::createCommonSection();
|
||||
template InputSection<ELF32BE> *elf::createCommonSection();
|
||||
template InputSection<ELF64LE> *elf::createCommonSection();
|
||||
|
@ -1517,3 +1559,8 @@ template class elf::GdbIndexSection<ELF32LE>;
|
|||
template class elf::GdbIndexSection<ELF32BE>;
|
||||
template class elf::GdbIndexSection<ELF64LE>;
|
||||
template class elf::GdbIndexSection<ELF64BE>;
|
||||
|
||||
template class elf::EhFrameHeader<ELF32LE>;
|
||||
template class elf::EhFrameHeader<ELF32BE>;
|
||||
template class elf::EhFrameHeader<ELF64LE>;
|
||||
template class elf::EhFrameHeader<ELF64BE>;
|
||||
|
|
|
@ -529,6 +529,34 @@ private:
|
|||
uint32_t CuTypesOffset;
|
||||
};
|
||||
|
||||
// --eh-frame-hdr option tells linker to construct a header for all the
|
||||
// .eh_frame sections. This header is placed to a section named .eh_frame_hdr
|
||||
// and also to a PT_GNU_EH_FRAME segment.
|
||||
// At runtime the unwinder then can find all the PT_GNU_EH_FRAME segments by
|
||||
// calling dl_iterate_phdr.
|
||||
// This section contains a lookup table for quick binary search of FDEs.
|
||||
// Detailed info about internals can be found in Ian Lance Taylor's blog:
|
||||
// http://www.airs.com/blog/archives/460 (".eh_frame")
|
||||
// http://www.airs.com/blog/archives/462 (".eh_frame_hdr")
|
||||
template <class ELFT>
|
||||
class EhFrameHeader final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
public:
|
||||
EhFrameHeader();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
size_t getSize() const override;
|
||||
void addFde(uint32_t Pc, uint32_t FdeVA);
|
||||
|
||||
private:
|
||||
struct FdeData {
|
||||
uint32_t Pc;
|
||||
uint32_t FdeVA;
|
||||
};
|
||||
|
||||
std::vector<FdeData> Fdes;
|
||||
};
|
||||
|
||||
template <class ELFT> InputSection<ELFT> *createCommonSection();
|
||||
template <class ELFT> InputSection<ELFT> *createInterpSection();
|
||||
template <class ELFT> MergeInputSection<ELFT> *createCommentSection();
|
||||
|
@ -540,6 +568,7 @@ template <class ELFT> struct In {
|
|||
static DynamicSection<ELFT> *Dynamic;
|
||||
static StringTableSection<ELFT> *DynStrTab;
|
||||
static SymbolTableSection<ELFT> *DynSymTab;
|
||||
static EhFrameHeader<ELFT> *EhFrameHdr;
|
||||
static GnuHashTableSection<ELFT> *GnuHashTab;
|
||||
static GdbIndexSection<ELFT> *GdbIndex;
|
||||
static GotSection<ELFT> *Got;
|
||||
|
@ -563,6 +592,7 @@ template <class ELFT> InputSection<ELFT> *In<ELFT>::Common;
|
|||
template <class ELFT> DynamicSection<ELFT> *In<ELFT>::Dynamic;
|
||||
template <class ELFT> StringTableSection<ELFT> *In<ELFT>::DynStrTab;
|
||||
template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::DynSymTab;
|
||||
template <class ELFT> EhFrameHeader<ELFT> *In<ELFT>::EhFrameHdr;
|
||||
template <class ELFT> GdbIndexSection<ELFT> *In<ELFT>::GdbIndex;
|
||||
template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
|
||||
template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
|
||||
|
|
|
@ -261,7 +261,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
|||
}
|
||||
|
||||
if (Config->EhFrameHdr)
|
||||
Out<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
|
||||
In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
|
||||
|
||||
if (Config->GnuHash)
|
||||
In<ELFT>::GnuHashTab = make<GnuHashTableSection<ELFT>>();
|
||||
|
@ -976,12 +976,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
|
||||
// Dynamic section must be the last one in this list and dynamic
|
||||
// symbol table section (DynSymTab) must be the first one.
|
||||
finalizeSynthetic<ELFT>(
|
||||
{In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::HashTab,
|
||||
In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab,
|
||||
In<ELFT>::DynStrTab, In<ELFT>::GdbIndex, In<ELFT>::Got,
|
||||
In<ELFT>::MipsGot, In<ELFT>::GotPlt, In<ELFT>::RelaDyn,
|
||||
In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::Dynamic});
|
||||
finalizeSynthetic<ELFT>({In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab,
|
||||
In<ELFT>::HashTab, In<ELFT>::SymTab,
|
||||
In<ELFT>::ShStrTab, In<ELFT>::StrTab,
|
||||
In<ELFT>::DynStrTab, In<ELFT>::GdbIndex,
|
||||
In<ELFT>::Got, In<ELFT>::MipsGot, In<ELFT>::GotPlt,
|
||||
In<ELFT>::RelaDyn, In<ELFT>::RelaPlt, In<ELFT>::Plt,
|
||||
In<ELFT>::EhFrameHdr, In<ELFT>::Dynamic});
|
||||
}
|
||||
|
||||
template <class ELFT> bool Writer<ELFT>::needsGot() {
|
||||
|
@ -1051,7 +1052,7 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
|
|||
if (!In<ELFT>::Plt->empty())
|
||||
addInputSec(In<ELFT>::Plt);
|
||||
if (!Out<ELFT>::EhFrame->empty())
|
||||
Add(Out<ELFT>::EhFrameHdr);
|
||||
addInputSec(In<ELFT>::EhFrameHdr);
|
||||
if (Out<ELFT>::Bss->Size > 0)
|
||||
Add(Out<ELFT>::Bss);
|
||||
}
|
||||
|
@ -1202,9 +1203,10 @@ template <class ELFT> std::vector<PhdrEntry<ELFT>> Writer<ELFT>::createPhdrs() {
|
|||
Ret.push_back(std::move(RelRo));
|
||||
|
||||
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
|
||||
if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr) {
|
||||
Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME, Out<ELFT>::EhFrameHdr->getPhdrFlags());
|
||||
Hdr.add(Out<ELFT>::EhFrameHdr);
|
||||
if (!Out<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr) {
|
||||
Phdr &Hdr =
|
||||
*AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->OutSec->getPhdrFlags());
|
||||
Hdr.add(In<ELFT>::EhFrameHdr->OutSec);
|
||||
}
|
||||
|
||||
// PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the
|
||||
|
@ -1523,14 +1525,16 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
|
|||
Out<ELFT>::Opd->writeTo(Buf + Out<ELFT>::Opd->Offset);
|
||||
}
|
||||
|
||||
OutputSectionBase *EhFrameHdr =
|
||||
In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr;
|
||||
for (OutputSectionBase *Sec : OutputSections)
|
||||
if (Sec != Out<ELFT>::Opd && Sec != Out<ELFT>::EhFrameHdr)
|
||||
if (Sec != Out<ELFT>::Opd && Sec != EhFrameHdr)
|
||||
Sec->writeTo(Buf + Sec->Offset);
|
||||
|
||||
// The .eh_frame_hdr depends on .eh_frame section contents, therefore
|
||||
// it should be written after .eh_frame is written.
|
||||
if (!Out<ELFT>::EhFrame->empty() && Out<ELFT>::EhFrameHdr)
|
||||
Out<ELFT>::EhFrameHdr->writeTo(Buf + Out<ELFT>::EhFrameHdr->Offset);
|
||||
if (!Out<ELFT>::EhFrame->empty() && EhFrameHdr)
|
||||
EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset);
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||
|
|
Loading…
Reference in New Issue