diff options
Diffstat (limited to 'ELF/InputSection.h')
-rw-r--r-- | ELF/InputSection.h | 206 |
1 files changed, 142 insertions, 64 deletions
diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 26956c72a960..61a89c540c5d 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -11,12 +11,22 @@ #define LLD_ELF_INPUT_SECTION_H #include "Config.h" +#include "Relocations.h" +#include "Thunks.h" #include "lld/Core/LLVM.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" namespace lld { -namespace elf2 { +namespace elf { +template <class ELFT> bool isDiscarded(InputSectionBase<ELFT> *S); + +class SymbolBody; + +template <class ELFT> class ICF; +template <class ELFT> class DefinedRegular; template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; template <class ELFT> class OutputSectionBase; @@ -24,120 +34,148 @@ template <class ELFT> class OutputSectionBase; // This corresponds to a section of an input file. template <class ELFT> class InputSectionBase { protected: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Chdr Elf_Chdr; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; const Elf_Shdr *Header; // The file this section is from. ObjectFile<ELFT> *File; + // If a section is compressed, this vector has uncompressed section data. + SmallVector<char, 0> Uncompressed; + public: - enum Kind { Regular, EHFrame, Merge, MipsReginfo }; + enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; Kind SectionKind; + InputSectionBase() : Repl(this) {} + InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header, Kind SectionKind); OutputSectionBase<ELFT> *OutSec = nullptr; + uint32_t Alignment; // Used for garbage collection. - // Live bit makes sense only when Config->GcSections is true. - bool isLive() const { return !Config->GcSections || Live; } - bool Live = false; + bool Live; + + // This pointer points to the "real" instance of this instance. + // Usually Repl == this. However, if ICF merges two sections, + // Repl pointer of one section points to another section. So, + // if you need to get a pointer to this instance, do not use + // this but instead this->Repl. + InputSectionBase<ELFT> *Repl; // Returns the size of this section (even if this is a common or BSS.) - size_t getSize() const { return Header->sh_size; } + size_t getSize() const; static InputSectionBase<ELFT> Discarded; StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } ObjectFile<ELFT> *getFile() const { return File; } - - // The writer sets and uses the addresses. - uintX_t getAlign() { - // The ELF spec states that a value of 0 means the section has no alignment - // constraits. - return std::max<uintX_t>(Header->sh_addralign, 1); - } - - uintX_t getOffset(const Elf_Sym &Sym); + uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const; // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; ArrayRef<uint8_t> getSectionData() const; - // Returns a section that Rel is pointing to. Used by the garbage collector. - InputSectionBase<ELFT> *getRelocTarget(const Elf_Rel &Rel); - InputSectionBase<ELFT> *getRelocTarget(const Elf_Rela &Rel); + void uncompress(); + + void relocate(uint8_t *Buf, uint8_t *BufEnd); + std::vector<Relocation<ELFT>> Relocations; + + bool Compressed; +}; + +template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded; + +// SectionPiece represents a piece of splittable section contents. +struct SectionPiece { + SectionPiece(size_t Off, ArrayRef<uint8_t> Data) + : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()), + Live(!Config->GcSections) {} - template <bool isRela> - using RelIteratorRange = - llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, isRela> *>; + ArrayRef<uint8_t> data() { return {Data, Size}; } + size_t size() const { return Size; } - template <bool isRela> - void relocate(uint8_t *Buf, uint8_t *BufEnd, RelIteratorRange<isRela> Rels); + size_t InputOff; + size_t OutputOff = -1; private: - template <bool isRela> - uint8_t *findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex, uint32_t Type, - RelIteratorRange<isRela> Rels); -}; + // We use bitfields because SplitInputSection is accessed by + // std::upper_bound very often. + // We want to save bits to make it cache friendly. + const uint8_t *Data; + uint32_t Size : 31; -template <class ELFT> -InputSectionBase<ELFT> - InputSectionBase<ELFT>::Discarded(nullptr, nullptr, - InputSectionBase<ELFT>::Regular); +public: + uint32_t Live : 1; +}; // Usually sections are copied to the output as atomic chunks of data, // but some special types of sections are split into small pieces of data // and each piece is copied to a different place in the output. // This class represents such special sections. template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; public: SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header, typename InputSectionBase<ELFT>::Kind SectionKind); - // For each piece of data, we maintain the offsets in the input section and - // in the output section. The latter may be -1 if it is not assigned yet. - std::vector<std::pair<uintX_t, uintX_t>> Offsets; + // Splittable sections are handled as a sequence of data + // rather than a single large blob of data. + std::vector<SectionPiece> Pieces; - std::pair<std::pair<uintX_t, uintX_t> *, uintX_t> - getRangeAndSize(uintX_t Offset); + // Returns the SectionPiece at a given input section offset. + SectionPiece *getSectionPiece(uintX_t Offset); + const SectionPiece *getSectionPiece(uintX_t Offset) const; }; // This corresponds to a SHF_MERGE section of an input file. template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::Shdr Elf_Shdr; public: MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase<ELFT> *S); - // Translate an offset in the input section to an offset in the output - // section. - uintX_t getOffset(uintX_t Offset); + void splitIntoPieces(); + + // Mark the piece at a given offset live. Used by GC. + void markLiveAt(uintX_t Offset) { LiveOffsets.insert(Offset); } + + // Translate an offset in the input section to an offset + // in the output section. + uintX_t getOffset(uintX_t Offset) const; + + void finalizePieces(); + +private: + llvm::DenseMap<uintX_t, uintX_t> OffsetMap; + llvm::DenseSet<uintX_t> LiveOffsets; }; // This corresponds to a .eh_frame section of an input file. -template <class ELFT> class EHInputSection : public SplitInputSection<ELFT> { +template <class ELFT> class EhInputSection : public SplitInputSection<ELFT> { public: - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; - EHInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint uintX_t; + EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase<ELFT> *S); + void split(); // Translate an offset in the input section to an offset in the output // section. - uintX_t getOffset(uintX_t Offset); + uintX_t getOffset(uintX_t Offset) const; // Relocation section that refer to this one. const Elf_Shdr *RelocSection = nullptr; @@ -145,12 +183,13 @@ public: // This corresponds to a non SHF_MERGE section of an input file. template <class ELFT> class InputSection : public InputSectionBase<ELFT> { + friend ICF<ELFT>; typedef InputSectionBase<ELFT> Base; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; - typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; - typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Rel Elf_Rel; + typedef typename ELFT::Sym Elf_Sym; + typedef typename ELFT::uint uintX_t; public: InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header); @@ -160,13 +199,41 @@ public: void writeTo(uint8_t *Buf); // Relocation sections that refer to this one. - SmallVector<const Elf_Shdr *, 1> RelocSections; + llvm::TinyPtrVector<const Elf_Shdr *> RelocSections; // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; static bool classof(const InputSectionBase<ELFT> *S); + + InputSectionBase<ELFT> *getRelocatedSection(); + + // Register thunk related to the symbol. When the section is written + // to a mmap'ed file, target is requested to write an actual thunk code. + // Now thunks is supported for MIPS and ARM target only. + void addThunk(const Thunk<ELFT> *T); + + // The offset of synthetic thunk code from beginning of this section. + uint64_t getThunkOff() const; + + // Size of chunk with thunks code. + uint64_t getThunksSize() const; + + template <class RelTy> + void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + +private: + template <class RelTy> + void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + + // Called by ICF to merge two input sections. + void replace(InputSection<ELFT> *Other); + + // Used by ICF. + uint64_t GroupId = 0; + + llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks; }; // MIPS .reginfo section provides information on the registers used by the code @@ -177,16 +244,27 @@ public: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf template <class ELFT> class MipsReginfoInputSection : public InputSectionBase<ELFT> { - typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFT::Shdr Elf_Shdr; public: MipsReginfoInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr); static bool classof(const InputSectionBase<ELFT> *S); - const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo; + const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr; +}; + +template <class ELFT> +class MipsOptionsInputSection : public InputSectionBase<ELFT> { + typedef typename ELFT::Shdr Elf_Shdr; + +public: + MipsOptionsInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Hdr); + static bool classof(const InputSectionBase<ELFT> *S); + + const llvm::object::Elf_Mips_RegInfo<ELFT> *Reginfo = nullptr; }; -} // namespace elf2 +} // namespace elf } // namespace lld #endif |