From 952eb4d348cb7a2d7632ee85529371d4fed24033 Mon Sep 17 00:00:00 2001 From: Eugene Leviant Date: Mon, 21 Nov 2016 15:52:10 +0000 Subject: [PATCH] [ELF] Convert EhFrameHeader to input section Differential revision: https://reviews.llvm.org/D26906 llvm-svn: 287549 --- lld/ELF/OutputSections.cpp | 49 ++----------------------------------------- lld/ELF/OutputSections.h | 34 ------------------------------ lld/ELF/SyntheticSections.cpp | 47 +++++++++++++++++++++++++++++++++++++++++ lld/ELF/SyntheticSections.h | 30 ++++++++++++++++++++++++++ lld/ELF/Writer.cpp | 32 +++++++++++++++------------- 5 files changed, 97 insertions(+), 95 deletions(-) diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 85635e7..9f22a4f 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -68,46 +68,6 @@ void OutputSectionBase::writeHeaderTo(typename ELFT::Shdr *Shdr) { static unsigned getVerDefNum() { return Config->VersionDefinitions.size() + 1; } template -EhFrameHeader::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 void EhFrameHeader::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(Buf + 4, Out::EhFrame->Addr - this->Addr - 4); - write32(Buf + 8, Fdes.size()); - Buf += 12; - - uintX_t VA = this->Addr; - for (FdeData &Fde : Fdes) { - write32(Buf, Fde.Pc - VA); - write32(Buf + 4, Fde.FdeVA - VA); - Buf += 8; - } -} - -template void EhFrameHeader::finalize() { - // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. - this->Size = 12 + Out::EhFrame->NumFdes * 8; -} - -template void EhFrameHeader::addFde(uint32_t Pc, uint32_t FdeVA) { Fdes.push_back({Pc, FdeVA}); } @@ -500,13 +460,13 @@ template void EhOutputSection::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::EhFrameHdr) { + if (In::EhFrameHdr) { for (CieRecord *Cie : Cies) { uint8_t Enc = getFdeEncoding(Cie->Piece->data()); for (SectionPiece *Fde : Cie->FdePieces) { uintX_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); uintX_t FdeVA = this->Addr + Fde->OutputOff; - Out::EhFrameHdr->addFde(Pc, FdeVA); + In::EhFrameHdr->addFde(Pc, FdeVA); } } } @@ -828,11 +788,6 @@ template void OutputSectionBase::writeHeaderTo(ELF32BE::Shdr *Shdr); template void OutputSectionBase::writeHeaderTo(ELF64LE::Shdr *Shdr); template void OutputSectionBase::writeHeaderTo(ELF64BE::Shdr *Shdr); -template class EhFrameHeader; -template class EhFrameHeader; -template class EhFrameHeader; -template class EhFrameHeader; - template class OutputSection; template class OutputSection; template class OutputSection; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 43995c7..1431ab9 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -42,7 +42,6 @@ public: enum Kind { Base, EHFrame, - EHFrameHdr, Merge, Regular, VersDef, @@ -272,37 +271,6 @@ private: llvm::DenseMap, 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 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 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 struct Out { typedef typename ELFT::Phdr Elf_Phdr; static uint8_t First; - static EhFrameHeader *EhFrameHdr; static EhOutputSection *EhFrame; static OutputSection *Bss; static OutputSection *MipsRldMap; @@ -363,7 +330,6 @@ template uint64_t getHeaderSize() { } template uint8_t Out::First; -template EhFrameHeader *Out::EhFrameHdr; template EhOutputSection *Out::EhFrame; template OutputSection *Out::Bss; template OutputSection *Out::MipsRldMap; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 65ca423..3feec78 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -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 using namespace llvm; +using namespace llvm::dwarf; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; @@ -1403,6 +1405,46 @@ template void GdbIndexSection::writeTo(uint8_t *Buf) { } } +template +EhFrameHeader::EhFrameHeader() + : SyntheticSection(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 void EhFrameHeader::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(Buf + 4, Out::EhFrame->Addr - this->getVA() - 4); + write32(Buf + 8, Fdes.size()); + Buf += 12; + + uintX_t VA = this->getVA(); + for (FdeData &Fde : Fdes) { + write32(Buf, Fde.Pc - VA); + write32(Buf + 4, Fde.FdeVA - VA); + Buf += 8; + } +} + +template size_t EhFrameHeader::getSize() const { + // .eh_frame_hdr has a 12 bytes header followed by an array of FDEs. + return 12 + Out::EhFrame->NumFdes * 8; +} + template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); template InputSection *elf::createCommonSection(); @@ -1517,3 +1559,8 @@ template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; template class elf::GdbIndexSection; + +template class elf::EhFrameHeader; +template class elf::EhFrameHeader; +template class elf::EhFrameHeader; +template class elf::EhFrameHeader; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 106e84e..bb42915 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -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 EhFrameHeader final : public SyntheticSection { + 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 Fdes; +}; + template InputSection *createCommonSection(); template InputSection *createInterpSection(); template MergeInputSection *createCommentSection(); @@ -540,6 +568,7 @@ template struct In { static DynamicSection *Dynamic; static StringTableSection *DynStrTab; static SymbolTableSection *DynSymTab; + static EhFrameHeader *EhFrameHdr; static GnuHashTableSection *GnuHashTab; static GdbIndexSection *GdbIndex; static GotSection *Got; @@ -563,6 +592,7 @@ template InputSection *In::Common; template DynamicSection *In::Dynamic; template StringTableSection *In::DynStrTab; template SymbolTableSection *In::DynSymTab; +template EhFrameHeader *In::EhFrameHdr; template GdbIndexSection *In::GdbIndex; template GnuHashTableSection *In::GnuHashTab; template GotSection *In::Got; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 64c80b9..ca6b76f 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -261,7 +261,7 @@ template void Writer::createSyntheticSections() { } if (Config->EhFrameHdr) - Out::EhFrameHdr = make>(); + In::EhFrameHdr = make>(); if (Config->GnuHash) In::GnuHashTab = make>(); @@ -976,12 +976,13 @@ template void Writer::finalizeSections() { // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. - finalizeSynthetic( - {In::DynSymTab, In::GnuHashTab, In::HashTab, - In::SymTab, In::ShStrTab, In::StrTab, - In::DynStrTab, In::GdbIndex, In::Got, - In::MipsGot, In::GotPlt, In::RelaDyn, - In::RelaPlt, In::Plt, In::Dynamic}); + finalizeSynthetic({In::DynSymTab, In::GnuHashTab, + In::HashTab, In::SymTab, + In::ShStrTab, In::StrTab, + In::DynStrTab, In::GdbIndex, + In::Got, In::MipsGot, In::GotPlt, + In::RelaDyn, In::RelaPlt, In::Plt, + In::EhFrameHdr, In::Dynamic}); } template bool Writer::needsGot() { @@ -1051,7 +1052,7 @@ template void Writer::addPredefinedSections() { if (!In::Plt->empty()) addInputSec(In::Plt); if (!Out::EhFrame->empty()) - Add(Out::EhFrameHdr); + addInputSec(In::EhFrameHdr); if (Out::Bss->Size > 0) Add(Out::Bss); } @@ -1202,9 +1203,10 @@ template std::vector> Writer::createPhdrs() { Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. - if (!Out::EhFrame->empty() && Out::EhFrameHdr) { - Phdr &Hdr = *AddHdr(PT_GNU_EH_FRAME, Out::EhFrameHdr->getPhdrFlags()); - Hdr.add(Out::EhFrameHdr); + if (!Out::EhFrame->empty() && In::EhFrameHdr) { + Phdr &Hdr = + *AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()); + Hdr.add(In::EhFrameHdr->OutSec); } // PT_OPENBSD_RANDOMIZE specifies the location and size of a part of the @@ -1523,14 +1525,16 @@ template void Writer::writeSections() { Out::Opd->writeTo(Buf + Out::Opd->Offset); } + OutputSectionBase *EhFrameHdr = + In::EhFrameHdr ? In::EhFrameHdr->OutSec : nullptr; for (OutputSectionBase *Sec : OutputSections) - if (Sec != Out::Opd && Sec != Out::EhFrameHdr) + if (Sec != Out::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::EhFrame->empty() && Out::EhFrameHdr) - Out::EhFrameHdr->writeTo(Buf + Out::EhFrameHdr->Offset); + if (!Out::EhFrame->empty() && EhFrameHdr) + EhFrameHdr->writeTo(Buf + EhFrameHdr->Offset); } template void Writer::writeBuildId() { -- 2.7.4