Convert EhOutputSection to be a synthetic section.
With this we complete the transition out of special output sections, and with the previous patches it should be possible to merge OutputSectionBase and OuputSection. llvm-svn: 296023
This commit is contained in:
parent
e199f285b0
commit
66b4e21534
@ -121,6 +121,8 @@ template <class ELFT>
|
||||
OutputSectionBase *InputSectionBase::getOutputSection() const {
|
||||
if (auto *MS = dyn_cast<MergeInputSection<ELFT>>(this))
|
||||
return MS->MergeSec ? MS->MergeSec->OutSec : nullptr;
|
||||
if (auto *EH = dyn_cast<EhInputSection<ELFT>>(this))
|
||||
return EH->EHSec->OutSec;
|
||||
return OutSec;
|
||||
}
|
||||
|
||||
@ -499,7 +501,7 @@ void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) {
|
||||
uint8_t *BufLoc = Buf + Offset;
|
||||
uint32_t Type = Rel.Type;
|
||||
|
||||
uintX_t AddrLoc = OutSec->Addr + Offset;
|
||||
uintX_t AddrLoc = getOutputSection<ELFT>()->Addr + Offset;
|
||||
RelExpr Expr = Rel.Expr;
|
||||
uint64_t TargetVA = SignExtend64<Bits>(
|
||||
getRelocTargetVA<ELFT>(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr));
|
||||
|
||||
@ -28,6 +28,7 @@ class SymbolBody;
|
||||
struct SectionPiece;
|
||||
|
||||
template <class ELFT> class DefinedRegular;
|
||||
template <class ELFT> class EhFrameSection;
|
||||
template <class ELFT> class MergeSyntheticSection;
|
||||
template <class ELFT> class ObjectFile;
|
||||
template <class ELFT> class OutputSection;
|
||||
@ -244,6 +245,7 @@ public:
|
||||
// Splittable sections are handled as a sequence of data
|
||||
// rather than a single large blob of data.
|
||||
std::vector<EhSectionPiece> Pieces;
|
||||
EhFrameSection<ELFT> *EHSec = nullptr;
|
||||
};
|
||||
|
||||
// This corresponds to a non SHF_MERGE section of an input file.
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include "OutputSections.h"
|
||||
#include "Config.h"
|
||||
#include "EhFrame.h"
|
||||
#include "LinkerScript.h"
|
||||
#include "Memory.h"
|
||||
#include "Strings.h"
|
||||
@ -269,217 +268,6 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
Script<ELFT>::X->writeDataBytes(this->Name, Buf);
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
EhOutputSection<ELFT>::EhOutputSection()
|
||||
: OutputSectionBase(".eh_frame", SHT_PROGBITS, SHF_ALLOC) {}
|
||||
|
||||
template <class ELFT>
|
||||
void EhOutputSection<ELFT>::forEachInputSection(
|
||||
std::function<void(InputSectionBase *)> F) {
|
||||
for (EhInputSection<ELFT> *S : Sections)
|
||||
F(S);
|
||||
}
|
||||
|
||||
// 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(EhSectionPiece &Piece,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
if (read32<E>(Piece.data().data() + 4) != 0)
|
||||
fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
|
||||
|
||||
SymbolBody *Personality = nullptr;
|
||||
unsigned FirstRelI = Piece.FirstRelocation;
|
||||
if (FirstRelI != (unsigned)-1)
|
||||
Personality =
|
||||
&Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
|
||||
|
||||
// Search for an existing CIE by CIE contents/relocation target pair.
|
||||
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
|
||||
|
||||
// If not found, create a new one.
|
||||
if (Cie->Piece == nullptr) {
|
||||
Cie->Piece = &Piece;
|
||||
Cies.push_back(Cie);
|
||||
}
|
||||
return Cie;
|
||||
}
|
||||
|
||||
// There is one FDE per function. Returns true if a given FDE
|
||||
// points to a live function.
|
||||
template <class ELFT>
|
||||
template <class RelTy>
|
||||
bool EhOutputSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
|
||||
unsigned FirstRelI = Piece.FirstRelocation;
|
||||
if (FirstRelI == (unsigned)-1)
|
||||
return false;
|
||||
const RelTy &Rel = Rels[FirstRelI];
|
||||
SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
|
||||
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
|
||||
if (!D || !D->Section)
|
||||
return false;
|
||||
InputSectionBase *Target = D->Section->Repl;
|
||||
return Target && Target->Live;
|
||||
}
|
||||
|
||||
// .eh_frame is a sequence of CIE or FDE records. In general, there
|
||||
// is one CIE record per input object file which is followed by
|
||||
// a list of FDEs. This function searches an existing CIE or create a new
|
||||
// one and associates FDEs to the CIE.
|
||||
template <class ELFT>
|
||||
template <class RelTy>
|
||||
void EhOutputSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
|
||||
DenseMap<size_t, CieRecord *> OffsetToCie;
|
||||
for (EhSectionPiece &Piece : Sec->Pieces) {
|
||||
// The empty record is the end marker.
|
||||
if (Piece.size() == 4)
|
||||
return;
|
||||
|
||||
size_t Offset = Piece.InputOff;
|
||||
uint32_t ID = read32<E>(Piece.data().data() + 4);
|
||||
if (ID == 0) {
|
||||
OffsetToCie[Offset] = addCie(Piece, Rels);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t CieOffset = Offset + 4 - ID;
|
||||
CieRecord *Cie = OffsetToCie[CieOffset];
|
||||
if (!Cie)
|
||||
fatal(toString(Sec) + ": invalid CIE reference");
|
||||
|
||||
if (!isFdeLive(Piece, Rels))
|
||||
continue;
|
||||
Cie->FdePieces.push_back(&Piece);
|
||||
NumFdes++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void EhOutputSection<ELFT>::addSection(InputSectionBase *C) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(C);
|
||||
Sec->OutSec = this;
|
||||
this->updateAlignment(Sec->Alignment);
|
||||
Sections.push_back(Sec);
|
||||
|
||||
// .eh_frame is a sequence of CIE or FDE records. This function
|
||||
// splits it into pieces so that we can call
|
||||
// SplitInputSection::getSectionPiece on the section.
|
||||
Sec->split();
|
||||
if (Sec->Pieces.empty())
|
||||
return;
|
||||
|
||||
if (Sec->NumRelocations) {
|
||||
if (Sec->AreRelocsRela)
|
||||
addSectionAux(Sec, Sec->template relas<ELFT>());
|
||||
else
|
||||
addSectionAux(Sec, Sec->template rels<ELFT>());
|
||||
return;
|
||||
}
|
||||
addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
|
||||
memcpy(Buf, D.data(), D.size());
|
||||
|
||||
// Fix the size field. -4 since size does not include the size field itself.
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
|
||||
}
|
||||
|
||||
template <class ELFT> void EhOutputSection<ELFT>::finalize() {
|
||||
if (this->Size)
|
||||
return; // Already finalized.
|
||||
|
||||
size_t Off = 0;
|
||||
for (CieRecord *Cie : Cies) {
|
||||
Cie->Piece->OutputOff = Off;
|
||||
Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
|
||||
|
||||
for (EhSectionPiece *Fde : Cie->FdePieces) {
|
||||
Fde->OutputOff = Off;
|
||||
Off += alignTo(Fde->size(), sizeof(uintX_t));
|
||||
}
|
||||
}
|
||||
this->Size = Off;
|
||||
}
|
||||
|
||||
template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
switch (Size) {
|
||||
case DW_EH_PE_udata2:
|
||||
return read16<E>(Buf);
|
||||
case DW_EH_PE_udata4:
|
||||
return read32<E>(Buf);
|
||||
case DW_EH_PE_udata8:
|
||||
return read64<E>(Buf);
|
||||
case DW_EH_PE_absptr:
|
||||
if (ELFT::Is64Bits)
|
||||
return read64<E>(Buf);
|
||||
return read32<E>(Buf);
|
||||
}
|
||||
fatal("unknown FDE size encoding");
|
||||
}
|
||||
|
||||
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
|
||||
// We need it to create .eh_frame_hdr section.
|
||||
template <class ELFT>
|
||||
typename ELFT::uint EhOutputSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
|
||||
uint8_t Enc) {
|
||||
// The starting address to which this FDE applies is
|
||||
// stored at FDE + 8 byte.
|
||||
size_t Off = FdeOff + 8;
|
||||
uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
|
||||
if ((Enc & 0x70) == DW_EH_PE_absptr)
|
||||
return Addr;
|
||||
if ((Enc & 0x70) == DW_EH_PE_pcrel)
|
||||
return Addr + this->Addr + Off;
|
||||
fatal("unknown FDE size relative encoding");
|
||||
}
|
||||
|
||||
template <class ELFT> void EhOutputSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
for (CieRecord *Cie : Cies) {
|
||||
size_t CieOffset = Cie->Piece->OutputOff;
|
||||
writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
|
||||
|
||||
for (EhSectionPiece *Fde : Cie->FdePieces) {
|
||||
size_t Off = Fde->OutputOff;
|
||||
writeCieFde<ELFT>(Buf + Off, Fde->data());
|
||||
|
||||
// FDE's second word should have the offset to an associated CIE.
|
||||
// Write it.
|
||||
write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
|
||||
}
|
||||
}
|
||||
|
||||
for (EhInputSection<ELFT> *S : Sections)
|
||||
S->template relocate<ELFT>(Buf, nullptr);
|
||||
|
||||
// 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 (In<ELFT>::EhFrameHdr) {
|
||||
for (CieRecord *Cie : Cies) {
|
||||
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
|
||||
for (SectionPiece *Fde : Cie->FdePieces) {
|
||||
uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
|
||||
uintX_t FdeVA = this->Addr + Fde->OutputOff;
|
||||
In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static typename ELFT::uint getOutFlags(InputSectionBase *S) {
|
||||
return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED;
|
||||
@ -596,7 +384,7 @@ void OutputSectionFactory<ELFT>::addInputSec(InputSectionBase *IS,
|
||||
} else {
|
||||
uint32_t Type = IS->Type;
|
||||
if (IS->kind() == InputSectionBase::EHFrame) {
|
||||
Out<ELFT>::EhFrame->addSection(IS);
|
||||
In<ELFT>::EhFrame->addSection(IS);
|
||||
return;
|
||||
}
|
||||
Sec = make<OutputSection<ELFT>>(Key.Name, Type, Flags);
|
||||
@ -639,11 +427,6 @@ template class OutputSection<ELF32BE>;
|
||||
template class OutputSection<ELF64LE>;
|
||||
template class OutputSection<ELF64BE>;
|
||||
|
||||
template class EhOutputSection<ELF32LE>;
|
||||
template class EhOutputSection<ELF32BE>;
|
||||
template class EhOutputSection<ELF64LE>;
|
||||
template class EhOutputSection<ELF64BE>;
|
||||
|
||||
template class OutputSectionFactory<ELF32LE>;
|
||||
template class OutputSectionFactory<ELF32BE>;
|
||||
template class OutputSectionFactory<ELF64LE>;
|
||||
|
||||
@ -129,52 +129,6 @@ public:
|
||||
uint8_t *Loc = nullptr;
|
||||
};
|
||||
|
||||
struct CieRecord {
|
||||
EhSectionPiece *Piece = nullptr;
|
||||
std::vector<EhSectionPiece *> FdePieces;
|
||||
};
|
||||
|
||||
// Output section for .eh_frame.
|
||||
template <class ELFT> class EhOutputSection final : public OutputSectionBase {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
typedef typename ELFT::Shdr Elf_Shdr;
|
||||
typedef typename ELFT::Rel Elf_Rel;
|
||||
typedef typename ELFT::Rela Elf_Rela;
|
||||
|
||||
public:
|
||||
EhOutputSection();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void finalize() override;
|
||||
bool empty() const { return Sections.empty(); }
|
||||
void forEachInputSection(std::function<void(InputSectionBase *)> F) override;
|
||||
|
||||
void addSection(InputSectionBase *S) override;
|
||||
Kind getKind() const override { return EHFrame; }
|
||||
static bool classof(const OutputSectionBase *B) {
|
||||
return B->getKind() == EHFrame;
|
||||
}
|
||||
|
||||
size_t NumFdes = 0;
|
||||
|
||||
private:
|
||||
template <class RelTy>
|
||||
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
|
||||
|
||||
template <class RelTy>
|
||||
CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
|
||||
|
||||
template <class RelTy>
|
||||
bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
|
||||
|
||||
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
|
||||
|
||||
std::vector<EhInputSection<ELFT> *> Sections;
|
||||
std::vector<CieRecord *> Cies;
|
||||
|
||||
// CIE records are uniquified by their contents and personality functions.
|
||||
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
|
||||
};
|
||||
|
||||
// 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.
|
||||
@ -183,7 +137,6 @@ template <class ELFT> struct Out {
|
||||
typedef typename ELFT::Phdr Elf_Phdr;
|
||||
|
||||
static uint8_t First;
|
||||
static EhOutputSection<ELFT> *EhFrame;
|
||||
static OutputSection<ELFT> *Bss;
|
||||
static OutputSection<ELFT> *BssRelRo;
|
||||
static OutputSectionBase *Opd;
|
||||
@ -241,7 +194,6 @@ template <class ELFT> uint64_t getHeaderSize() {
|
||||
}
|
||||
|
||||
template <class ELFT> uint8_t Out<ELFT>::First;
|
||||
template <class ELFT> EhOutputSection<ELFT> *Out<ELFT>::EhFrame;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
|
||||
template <class ELFT> OutputSection<ELFT> *Out<ELFT>::BssRelRo;
|
||||
template <class ELFT> OutputSectionBase *Out<ELFT>::Opd;
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
class SymbolBody;
|
||||
class InputSectionData;
|
||||
class InputSection;
|
||||
class InputSectionBase;
|
||||
class OutputSectionBase;
|
||||
|
||||
@ -400,6 +400,210 @@ void BuildIdSection<ELFT>::writeBuildId(ArrayRef<uint8_t> Buf) {
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
EhFrameSection<ELFT>::EhFrameSection()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame") {}
|
||||
|
||||
// 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 *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
if (read32<E>(Piece.data().data() + 4) != 0)
|
||||
fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame");
|
||||
|
||||
SymbolBody *Personality = nullptr;
|
||||
unsigned FirstRelI = Piece.FirstRelocation;
|
||||
if (FirstRelI != (unsigned)-1)
|
||||
Personality =
|
||||
&Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
|
||||
|
||||
// Search for an existing CIE by CIE contents/relocation target pair.
|
||||
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
|
||||
|
||||
// If not found, create a new one.
|
||||
if (Cie->Piece == nullptr) {
|
||||
Cie->Piece = &Piece;
|
||||
Cies.push_back(Cie);
|
||||
}
|
||||
return Cie;
|
||||
}
|
||||
|
||||
// There is one FDE per function. Returns true if a given FDE
|
||||
// points to a live function.
|
||||
template <class ELFT>
|
||||
template <class RelTy>
|
||||
bool EhFrameSection<ELFT>::isFdeLive(EhSectionPiece &Piece,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(Piece.ID);
|
||||
unsigned FirstRelI = Piece.FirstRelocation;
|
||||
if (FirstRelI == (unsigned)-1)
|
||||
return false;
|
||||
const RelTy &Rel = Rels[FirstRelI];
|
||||
SymbolBody &B = Sec->template getFile<ELFT>()->getRelocTargetSym(Rel);
|
||||
auto *D = dyn_cast<DefinedRegular<ELFT>>(&B);
|
||||
if (!D || !D->Section)
|
||||
return false;
|
||||
InputSectionBase *Target = D->Section->Repl;
|
||||
return Target && Target->Live;
|
||||
}
|
||||
|
||||
// .eh_frame is a sequence of CIE or FDE records. In general, there
|
||||
// is one CIE record per input object file which is followed by
|
||||
// a list of FDEs. This function searches an existing CIE or create a new
|
||||
// one and associates FDEs to the CIE.
|
||||
template <class ELFT>
|
||||
template <class RelTy>
|
||||
void EhFrameSection<ELFT>::addSectionAux(EhInputSection<ELFT> *Sec,
|
||||
ArrayRef<RelTy> Rels) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
|
||||
DenseMap<size_t, CieRecord *> OffsetToCie;
|
||||
for (EhSectionPiece &Piece : Sec->Pieces) {
|
||||
// The empty record is the end marker.
|
||||
if (Piece.size() == 4)
|
||||
return;
|
||||
|
||||
size_t Offset = Piece.InputOff;
|
||||
uint32_t ID = read32<E>(Piece.data().data() + 4);
|
||||
if (ID == 0) {
|
||||
OffsetToCie[Offset] = addCie(Piece, Rels);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t CieOffset = Offset + 4 - ID;
|
||||
CieRecord *Cie = OffsetToCie[CieOffset];
|
||||
if (!Cie)
|
||||
fatal(toString(Sec) + ": invalid CIE reference");
|
||||
|
||||
if (!isFdeLive(Piece, Rels))
|
||||
continue;
|
||||
Cie->FdePieces.push_back(&Piece);
|
||||
NumFdes++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void EhFrameSection<ELFT>::addSection(InputSectionBase *C) {
|
||||
auto *Sec = cast<EhInputSection<ELFT>>(C);
|
||||
Sec->EHSec = this;
|
||||
updateAlignment(Sec->Alignment);
|
||||
Sections.push_back(Sec);
|
||||
|
||||
// .eh_frame is a sequence of CIE or FDE records. This function
|
||||
// splits it into pieces so that we can call
|
||||
// SplitInputSection::getSectionPiece on the section.
|
||||
Sec->split();
|
||||
if (Sec->Pieces.empty())
|
||||
return;
|
||||
|
||||
if (Sec->NumRelocations) {
|
||||
if (Sec->AreRelocsRela)
|
||||
addSectionAux(Sec, Sec->template relas<ELFT>());
|
||||
else
|
||||
addSectionAux(Sec, Sec->template rels<ELFT>());
|
||||
return;
|
||||
}
|
||||
addSectionAux(Sec, makeArrayRef<Elf_Rela>(nullptr, nullptr));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
|
||||
memcpy(Buf, D.data(), D.size());
|
||||
|
||||
// Fix the size field. -4 since size does not include the size field itself.
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
|
||||
}
|
||||
|
||||
template <class ELFT> void EhFrameSection<ELFT>::finalize() {
|
||||
if (this->Size)
|
||||
return; // Already finalized.
|
||||
|
||||
size_t Off = 0;
|
||||
for (CieRecord *Cie : Cies) {
|
||||
Cie->Piece->OutputOff = Off;
|
||||
Off += alignTo(Cie->Piece->size(), sizeof(uintX_t));
|
||||
|
||||
for (EhSectionPiece *Fde : Cie->FdePieces) {
|
||||
Fde->OutputOff = Off;
|
||||
Off += alignTo(Fde->size(), sizeof(uintX_t));
|
||||
}
|
||||
}
|
||||
this->Size = Off;
|
||||
}
|
||||
|
||||
template <class ELFT> static uint64_t readFdeAddr(uint8_t *Buf, int Size) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
switch (Size) {
|
||||
case DW_EH_PE_udata2:
|
||||
return read16<E>(Buf);
|
||||
case DW_EH_PE_udata4:
|
||||
return read32<E>(Buf);
|
||||
case DW_EH_PE_udata8:
|
||||
return read64<E>(Buf);
|
||||
case DW_EH_PE_absptr:
|
||||
if (ELFT::Is64Bits)
|
||||
return read64<E>(Buf);
|
||||
return read32<E>(Buf);
|
||||
}
|
||||
fatal("unknown FDE size encoding");
|
||||
}
|
||||
|
||||
// Returns the VA to which a given FDE (on a mmap'ed buffer) is applied to.
|
||||
// We need it to create .eh_frame_hdr section.
|
||||
template <class ELFT>
|
||||
typename ELFT::uint EhFrameSection<ELFT>::getFdePc(uint8_t *Buf, size_t FdeOff,
|
||||
uint8_t Enc) {
|
||||
// The starting address to which this FDE applies is
|
||||
// stored at FDE + 8 byte.
|
||||
size_t Off = FdeOff + 8;
|
||||
uint64_t Addr = readFdeAddr<ELFT>(Buf + Off, Enc & 0x7);
|
||||
if ((Enc & 0x70) == DW_EH_PE_absptr)
|
||||
return Addr;
|
||||
if ((Enc & 0x70) == DW_EH_PE_pcrel)
|
||||
return Addr + this->OutSec->Addr + Off;
|
||||
fatal("unknown FDE size relative encoding");
|
||||
}
|
||||
|
||||
template <class ELFT> void EhFrameSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const endianness E = ELFT::TargetEndianness;
|
||||
for (CieRecord *Cie : Cies) {
|
||||
size_t CieOffset = Cie->Piece->OutputOff;
|
||||
writeCieFde<ELFT>(Buf + CieOffset, Cie->Piece->data());
|
||||
|
||||
for (EhSectionPiece *Fde : Cie->FdePieces) {
|
||||
size_t Off = Fde->OutputOff;
|
||||
writeCieFde<ELFT>(Buf + Off, Fde->data());
|
||||
|
||||
// FDE's second word should have the offset to an associated CIE.
|
||||
// Write it.
|
||||
write32<E>(Buf + Off + 4, Off + 4 - CieOffset);
|
||||
}
|
||||
}
|
||||
|
||||
for (EhInputSection<ELFT> *S : Sections)
|
||||
S->template relocate<ELFT>(Buf, nullptr);
|
||||
|
||||
// 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 (In<ELFT>::EhFrameHdr) {
|
||||
for (CieRecord *Cie : Cies) {
|
||||
uint8_t Enc = getFdeEncoding<ELFT>(Cie->Piece);
|
||||
for (SectionPiece *Fde : Cie->FdePieces) {
|
||||
uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
|
||||
uintX_t FdeVA = this->OutSec->Addr + Fde->OutputOff;
|
||||
In<ELFT>::EhFrameHdr->addFde(Pc, FdeVA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
GotSection<ELFT>::GotSection()
|
||||
: SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
|
||||
@ -1675,7 +1879,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
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 + 4, In<ELFT>::EhFrame->OutSec->Addr - this->getVA() - 4);
|
||||
write32<E>(Buf + 8, Fdes.size());
|
||||
Buf += 12;
|
||||
|
||||
@ -1689,7 +1893,7 @@ template <class ELFT> void EhFrameHeader<ELFT>::writeTo(uint8_t *Buf) {
|
||||
|
||||
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;
|
||||
return 12 + In<ELFT>::EhFrame->NumFdes * 8;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -1698,7 +1902,7 @@ void EhFrameHeader<ELFT>::addFde(uint32_t Pc, uint32_t FdeVA) {
|
||||
}
|
||||
|
||||
template <class ELFT> bool EhFrameHeader<ELFT>::empty() const {
|
||||
return Out<ELFT>::EhFrame->empty();
|
||||
return In<ELFT>::EhFrame->empty();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -2158,3 +2362,8 @@ template class elf::ThunkSection<ELF32LE>;
|
||||
template class elf::ThunkSection<ELF32BE>;
|
||||
template class elf::ThunkSection<ELF64LE>;
|
||||
template class elf::ThunkSection<ELF64BE>;
|
||||
|
||||
template class elf::EhFrameSection<ELF32LE>;
|
||||
template class elf::EhFrameSection<ELF32BE>;
|
||||
template class elf::EhFrameSection<ELF64LE>;
|
||||
template class elf::EhFrameSection<ELF64BE>;
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#ifndef LLD_ELF_SYNTHETIC_SECTION_H
|
||||
#define LLD_ELF_SYNTHETIC_SECTION_H
|
||||
|
||||
#include "EhFrame.h"
|
||||
#include "GdbIndex.h"
|
||||
#include "InputSection.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
@ -59,6 +60,55 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct CieRecord {
|
||||
EhSectionPiece *Piece = nullptr;
|
||||
std::vector<EhSectionPiece *> FdePieces;
|
||||
};
|
||||
|
||||
// Section for .eh_frame.
|
||||
template <class ELFT>
|
||||
class EhFrameSection final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
typedef typename ELFT::Shdr Elf_Shdr;
|
||||
typedef typename ELFT::Rel Elf_Rel;
|
||||
typedef typename ELFT::Rela Elf_Rela;
|
||||
|
||||
void updateAlignment(uint64_t Val) {
|
||||
if (Val > this->Alignment)
|
||||
this->Alignment = Val;
|
||||
}
|
||||
|
||||
public:
|
||||
EhFrameSection();
|
||||
void writeTo(uint8_t *Buf) override;
|
||||
void finalize() override;
|
||||
bool empty() const override { return Sections.empty(); }
|
||||
size_t getSize() const override { return Size; }
|
||||
|
||||
void addSection(InputSectionBase *S);
|
||||
|
||||
size_t NumFdes = 0;
|
||||
|
||||
private:
|
||||
uint64_t Size = 0;
|
||||
template <class RelTy>
|
||||
void addSectionAux(EhInputSection<ELFT> *S, llvm::ArrayRef<RelTy> Rels);
|
||||
|
||||
template <class RelTy>
|
||||
CieRecord *addCie(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
|
||||
|
||||
template <class RelTy>
|
||||
bool isFdeLive(EhSectionPiece &Piece, ArrayRef<RelTy> Rels);
|
||||
|
||||
uintX_t getFdePc(uint8_t *Buf, size_t Off, uint8_t Enc);
|
||||
|
||||
std::vector<EhInputSection<ELFT> *> Sections;
|
||||
std::vector<CieRecord *> Cies;
|
||||
|
||||
// CIE records are uniquified by their contents and personality functions.
|
||||
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
|
||||
};
|
||||
|
||||
template <class ELFT> class GotSection final : public SyntheticSection<ELFT> {
|
||||
typedef typename ELFT::uint uintX_t;
|
||||
|
||||
@ -762,6 +812,7 @@ template <class ELFT> struct In {
|
||||
static GnuHashTableSection<ELFT> *GnuHashTab;
|
||||
static GdbIndexSection<ELFT> *GdbIndex;
|
||||
static GotSection<ELFT> *Got;
|
||||
static EhFrameSection<ELFT> *EhFrame;
|
||||
static MipsGotSection<ELFT> *MipsGot;
|
||||
static GotPltSection<ELFT> *GotPlt;
|
||||
static IgotPltSection<ELFT> *IgotPlt;
|
||||
@ -791,6 +842,7 @@ 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;
|
||||
template <class ELFT> EhFrameSection<ELFT> *In<ELFT>::EhFrame;
|
||||
template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
|
||||
template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
|
||||
template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
|
||||
|
||||
@ -318,7 +318,6 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
SHF_ALLOC | SHF_WRITE);
|
||||
In<ELFT>::DynStrTab = make<StringTableSection<ELFT>>(".dynstr", true);
|
||||
In<ELFT>::Dynamic = make<DynamicSection<ELFT>>();
|
||||
Out<ELFT>::EhFrame = make<EhOutputSection<ELFT>>();
|
||||
In<ELFT>::RelaDyn = make<RelocationSection<ELFT>>(
|
||||
Config->Rela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc);
|
||||
In<ELFT>::ShStrTab = make<StringTableSection<ELFT>>(".shstrtab", false);
|
||||
@ -444,6 +443,11 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
|
||||
Add(In<ELFT>::EhFrameHdr);
|
||||
}
|
||||
|
||||
if (!Config->Relocatable) {
|
||||
In<ELFT>::EhFrame = make<EhFrameSection<ELFT>>();
|
||||
Add(In<ELFT>::EhFrame);
|
||||
}
|
||||
|
||||
if (In<ELFT>::SymTab)
|
||||
Add(In<ELFT>::SymTab);
|
||||
Add(In<ELFT>::ShStrTab);
|
||||
@ -1088,10 +1092,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// Define __rel[a]_iplt_{start,end} symbols if needed.
|
||||
addRelIpltSymbols();
|
||||
|
||||
if (!Out<ELFT>::EhFrame->empty()) {
|
||||
OutputSections.push_back(Out<ELFT>::EhFrame);
|
||||
Out<ELFT>::EhFrame->finalize();
|
||||
}
|
||||
// This responsible for splitting up .eh_frame section into
|
||||
// pieces. The relocation scan uses those peaces, so this has to be
|
||||
// earlier.
|
||||
finalizeSynthetic<ELFT>({In<ELFT>::EhFrame});
|
||||
|
||||
// Scan relocations. This must be done after every symbol is declared so that
|
||||
// we can correctly decide if a dynamic relocation is needed.
|
||||
@ -1323,7 +1327,7 @@ template <class ELFT> std::vector<PhdrEntry> 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() && In<ELFT>::EhFrameHdr)
|
||||
if (!In<ELFT>::EhFrame->empty() && In<ELFT>::EhFrameHdr)
|
||||
AddHdr(PT_GNU_EH_FRAME, In<ELFT>::EhFrameHdr->OutSec->getPhdrFlags())
|
||||
->add(In<ELFT>::EhFrameHdr->OutSec);
|
||||
|
||||
@ -1827,7 +1831,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() {
|
||||
|
||||
// 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() && EhFrameHdr)
|
||||
if (EhFrameHdr)
|
||||
EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ local:
|
||||
|
||||
// CHECK: Address Size Align Out In File Symbol
|
||||
// CHECK-NEXT: 0000000000200158 0000000000000030 8 .eh_frame
|
||||
// CHECK-NEXT: 0000000000200158 0000000000000030 8 .eh_frame
|
||||
// CHECK-NEXT: 0000000000201000 0000000000000015 4 .text
|
||||
// CHECK-NEXT: 0000000000201000 000000000000000e 4 .text
|
||||
// CHECK-NEXT: 0000000000201000 000000000000000e 4 {{.*}}{{/|\\}}map-file.s.tmp1.o
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user