//===- InputSection.h -------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_INPUT_SECTION_H #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 elf { template bool isDiscarded(InputSectionBase *S); class SymbolBody; template class ICF; template class DefinedRegular; template class ObjectFile; template class OutputSection; template class OutputSectionBase; // This corresponds to a section of an input file. template class InputSectionBase { protected: 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 *File; // If a section is compressed, this vector has uncompressed section data. SmallVector Uncompressed; public: enum Kind { Regular, EHFrame, Merge, MipsReginfo, MipsOptions }; Kind SectionKind; InputSectionBase() : Repl(this) {} InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, Kind SectionKind); OutputSectionBase *OutSec = nullptr; uint32_t Alignment; // Used for garbage collection. 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 *Repl; // Returns the size of this section (even if this is a common or BSS.) size_t getSize() const; static InputSectionBase Discarded; StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } ObjectFile *getFile() const { return File; } uintX_t getOffset(const DefinedRegular &Sym) const; // Translate an offset in the input section to an offset in the output // section. uintX_t getOffset(uintX_t Offset) const; ArrayRef getSectionData() const; void uncompress(); void relocate(uint8_t *Buf, uint8_t *BufEnd); std::vector> Relocations; bool Compressed; }; template InputSectionBase InputSectionBase::Discarded; // SectionPiece represents a piece of splittable section contents. struct SectionPiece { SectionPiece(size_t Off, ArrayRef Data) : InputOff(Off), Data((const uint8_t *)Data.data()), Size(Data.size()), Live(!Config->GcSections) {} ArrayRef data() { return {Data, Size}; } size_t size() const { return Size; } size_t InputOff; size_t OutputOff = -1; private: // 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; 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 SplitInputSection : public InputSectionBase { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::uint uintX_t; public: SplitInputSection(ObjectFile *File, const Elf_Shdr *Header, typename InputSectionBase::Kind SectionKind); // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; // 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 MergeInputSection : public SplitInputSection { typedef typename ELFT::uint uintX_t; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::Shdr Elf_Shdr; public: MergeInputSection(ObjectFile *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase *S); 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 OffsetMap; llvm::DenseSet LiveOffsets; }; // This corresponds to a .eh_frame section of an input file. template class EhInputSection : public SplitInputSection { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::uint uintX_t; EhInputSection(ObjectFile *F, const Elf_Shdr *Header); static bool classof(const InputSectionBase *S); void split(); // Translate an offset in the input section to an offset in the output // section. uintX_t getOffset(uintX_t Offset) const; // Relocation section that refer to this one. const Elf_Shdr *RelocSection = nullptr; }; // This corresponds to a non SHF_MERGE section of an input file. template class InputSection : public InputSectionBase { friend ICF; typedef InputSectionBase Base; 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 *F, const Elf_Shdr *Header); // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. void writeTo(uint8_t *Buf); // Relocation sections that refer to this one. llvm::TinyPtrVector 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 *S); InputSectionBase *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 *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 void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef Rels); private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); // Called by ICF to merge two input sections. void replace(InputSection *Other); // Used by ICF. uint64_t GroupId = 0; llvm::TinyPtrVector *> Thunks; }; // MIPS .reginfo section provides information on the registers used by the code // in the object file. Linker should collect this information and write a single // .reginfo section in the output file. The output section contains a union of // used registers masks taken from input .reginfo sections and final value // of the `_gp` symbol. For details: Chapter 4 / "Register Information" at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf template class MipsReginfoInputSection : public InputSectionBase { typedef typename ELFT::Shdr Elf_Shdr; public: MipsReginfoInputSection(ObjectFile *F, const Elf_Shdr *Hdr); static bool classof(const InputSectionBase *S); const llvm::object::Elf_Mips_RegInfo *Reginfo = nullptr; }; template class MipsOptionsInputSection : public InputSectionBase { typedef typename ELFT::Shdr Elf_Shdr; public: MipsOptionsInputSection(ObjectFile *F, const Elf_Shdr *Hdr); static bool classof(const InputSectionBase *S); const llvm::object::Elf_Mips_RegInfo *Reginfo = nullptr; }; } // namespace elf } // namespace lld #endif