//===- 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/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" #include namespace lld { namespace elf { class DefinedCommon; class SymbolBody; struct SectionPiece; template class DefinedRegular; template class ObjectFile; template class OutputSection; class OutputSectionBase; // We need non-template input section class to store symbol layout // in linker script parser structures, where we do not have ELFT // template parameter. For each scripted output section symbol we // store pointer to preceding InputSectionData object or nullptr, // if symbol should be placed at the very beginning of the output // section class InputSectionData { public: enum Kind { Regular, EHFrame, Merge, Synthetic, }; // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. InputSectionData(Kind SectionKind, StringRef Name, ArrayRef Data, bool Live) : SectionKind(SectionKind), Live(Live), Assigned(false), Name(Name), Data(Data) {} private: unsigned SectionKind : 3; public: Kind kind() const { return (Kind)SectionKind; } unsigned Live : 1; // for garbage collection unsigned Assigned : 1; // for linker script uint32_t Alignment; StringRef Name; ArrayRef Data; template llvm::ArrayRef getDataAs() const { size_t S = Data.size(); assert(S % sizeof(T) == 0); return llvm::makeArrayRef((const T *)Data.data(), S / sizeof(T)); } std::vector Relocations; }; // This corresponds to a section of an input file. template class InputSectionBase : public InputSectionData { 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; // The file this section is from. ObjectFile *File; public: // These corresponds to the fields in Elf_Shdr. uintX_t Flags; uintX_t Offset = 0; uintX_t Entsize; uint32_t Type; uint32_t Link; uint32_t Info; InputSectionBase() : InputSectionData(Regular, "", ArrayRef(), false), Repl(this) { NumRelocations = 0; AreRelocsRela = false; } InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, StringRef Name, Kind SectionKind); InputSectionBase(ObjectFile *File, uintX_t Flags, uint32_t Type, uintX_t Entsize, uint32_t Link, uint32_t Info, uintX_t Addralign, ArrayRef Data, StringRef Name, Kind SectionKind); OutputSectionBase *OutSec = nullptr; // Relocations that refer to this section. const Elf_Rel *FirstRelocation = nullptr; unsigned NumRelocations : 31; unsigned AreRelocsRela : 1; ArrayRef rels() const { assert(!AreRelocsRela); return llvm::makeArrayRef(FirstRelocation, NumRelocations); } ArrayRef relas() const { assert(AreRelocsRela); return llvm::makeArrayRef(static_cast(FirstRelocation), NumRelocations); } // 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; ObjectFile *getFile() const { return File; } llvm::object::ELFFile getObj() const { return File->getObj(); } uintX_t getOffset(const DefinedRegular &Sym) const; InputSectionBase *getLinkOrderDep() const; // Translate an offset in the input section to an offset in the output // section. uintX_t getOffset(uintX_t Offset) const; void uncompress(); // Returns a source location string. Used to construct an error message. std::string getLocation(uintX_t Offset); void relocate(uint8_t *Buf, uint8_t *BufEnd); }; // SectionPiece represents a piece of splittable section contents. // We allocate a lot of these and binary search on them. This means that they // have to be as compact as possible, which is why we don't store the size (can // be found by looking at the next one) and put the hash in a side table. struct SectionPiece { SectionPiece(size_t Off, bool Live = false) : InputOff(Off), OutputOff(-1), Live(Live || !Config->GcSections) {} size_t InputOff; ssize_t OutputOff : 8 * sizeof(ssize_t) - 1; size_t Live : 1; }; static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t), "SectionPiece is too big"); // This corresponds to a SHF_MERGE section of an input file. template class MergeInputSection : public InputSectionBase { 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, StringRef Name); static bool classof(const InputSectionData *S); void splitIntoPieces(); // Mark the piece at a given offset live. Used by GC. void markLiveAt(uintX_t Offset) { assert(this->Flags & llvm::ELF::SHF_ALLOC); LiveOffsets.insert(Offset); } // Translate an offset in the input section to an offset // in the output section. uintX_t getOffset(uintX_t Offset) const; // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; // Returns I'th piece's data. This function is very hot when // string merging is enabled, so we want to inline. LLVM_ATTRIBUTE_ALWAYS_INLINE llvm::CachedHashStringRef getData(size_t I) const { size_t Begin = Pieces[I].InputOff; size_t End; if (Pieces.size() - 1 == I) End = this->Data.size(); else End = Pieces[I + 1].InputOff; StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin}; return {S, Hashes[I]}; } // Returns the SectionPiece at a given input section offset. SectionPiece *getSectionPiece(uintX_t Offset); const SectionPiece *getSectionPiece(uintX_t Offset) const; private: void splitStrings(ArrayRef A, size_t Size); void splitNonStrings(ArrayRef A, size_t Size); std::vector Hashes; mutable llvm::DenseMap OffsetMap; mutable std::once_flag InitOffsetMap; llvm::DenseSet LiveOffsets; }; struct EhSectionPiece : public SectionPiece { EhSectionPiece(size_t Off, InputSectionData *ID, uint32_t Size, unsigned FirstRelocation) : SectionPiece(Off, false), ID(ID), Size(Size), FirstRelocation(FirstRelocation) {} InputSectionData *ID; uint32_t Size; uint32_t size() const { return Size; } ArrayRef data() { return {ID->Data.data() + this->InputOff, Size}; } unsigned FirstRelocation; }; // This corresponds to a .eh_frame section of an input file. template class EhInputSection : public InputSectionBase { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::uint uintX_t; EhInputSection(ObjectFile *F, const Elf_Shdr *Header, StringRef Name); static bool classof(const InputSectionData *S); void split(); template void split(ArrayRef Rels); // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector Pieces; }; // This corresponds to a non SHF_MERGE section of an input file. template class InputSection : public InputSectionBase { 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; typedef InputSectionData::Kind Kind; public: InputSection(); InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign, ArrayRef Data, StringRef Name, Kind K = InputSectionData::Regular); InputSection(ObjectFile *F, const Elf_Shdr *Header, StringRef Name); static InputSection Discarded; // Write this section to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. void writeTo(uint8_t *Buf); // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; // InputSection that is dependent on us (reverse dependency for GC) InputSectionBase *DependentSection = nullptr; static bool classof(const InputSectionData *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); // Used by ICF. uint32_t Class[2] = {0, 0}; // Called by ICF to merge two input sections. void replace(InputSection *Other); private: template void copyRelocations(uint8_t *Buf, llvm::ArrayRef Rels); llvm::TinyPtrVector *> Thunks; }; template InputSection InputSection::Discarded; } // namespace elf template std::string toString(const elf::InputSectionBase *); } // namespace lld #endif