diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2017-02-23 22:06:28 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2017-02-23 22:06:28 +0000 |
commit | 66b4e2153414e4752c75bef37afbc3e4fdf7a67f (patch) | |
tree | 9791c9246948fa3b47eba3a9d4406a4e78561b0f /lld | |
parent | e199f285b099a31ed50c303c1d20499b1302fe53 (diff) | |
download | bcm5719-llvm-66b4e2153414e4752c75bef37afbc3e4fdf7a67f.tar.gz bcm5719-llvm-66b4e2153414e4752c75bef37afbc3e4fdf7a67f.zip |
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
Diffstat (limited to 'lld')
-rw-r--r-- | lld/ELF/InputSection.cpp | 4 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 2 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 219 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 48 | ||||
-rw-r--r-- | lld/ELF/Relocations.h | 1 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.cpp | 215 | ||||
-rw-r--r-- | lld/ELF/SyntheticSections.h | 52 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 18 | ||||
-rw-r--r-- | lld/test/ELF/map-file.s | 1 |
9 files changed, 282 insertions, 278 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 0d40c198676..6e9a7d78401 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -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)); diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h index 49733fc5fa2..0ad9ceba363 100644 --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -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. diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 10aeca5a5bb..7de2be2dc16 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -9,7 +9,6 @@ #include "OutputSections.h" #include "Config.h" -#include "EhFrame.h" #include "LinkerScript.h" #include "Memory.h" #include "Strings.h" @@ -270,217 +269,6 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *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>; diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index f1f45dda58e..bdd032015ad 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -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; diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index f07f74efb05..d1420cf37ac 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -15,7 +15,6 @@ namespace lld { namespace elf { class SymbolBody; -class InputSectionData; class InputSection; class InputSectionBase; class OutputSectionBase; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 0398249016e..d3575a1fb29 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -401,6 +401,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, Target->GotEntrySize, ".got") {} @@ -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>; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 43f3ee96dbb..98b6c8beeb1 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -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; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 35d9759565a..835f4d0bcde 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -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); } diff --git a/lld/test/ELF/map-file.s b/lld/test/ELF/map-file.s index e94937c5939..4b02aecd8de 100644 --- a/lld/test/ELF/map-file.s +++ b/lld/test/ELF/map-file.s @@ -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 |