| //===- 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 <mutex> |
| |
| namespace lld { |
| namespace elf { |
| |
| class DefinedCommon; |
| class SymbolBody; |
| struct SectionPiece; |
| |
| template <class ELFT> class DefinedRegular; |
| template <class ELFT> class ObjectFile; |
| template <class ELFT> 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<uint8_t> 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<uint8_t> Data; |
| |
| template <typename T> llvm::ArrayRef<T> getDataAs() const { |
| size_t S = Data.size(); |
| assert(S % sizeof(T) == 0); |
| return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T)); |
| } |
| |
| std::vector<Relocation> Relocations; |
| }; |
| |
| // This corresponds to a section of an input file. |
| template <class ELFT> 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<ELFT> *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<uint8_t>(), false), Repl(this) { |
| NumRelocations = 0; |
| AreRelocsRela = false; |
| } |
| |
| InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header, |
| StringRef Name, Kind SectionKind); |
| InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type, |
| uintX_t Entsize, uint32_t Link, uint32_t Info, |
| uintX_t Addralign, ArrayRef<uint8_t> 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<Elf_Rel> rels() const { |
| assert(!AreRelocsRela); |
| return llvm::makeArrayRef(FirstRelocation, NumRelocations); |
| } |
| ArrayRef<Elf_Rela> relas() const { |
| assert(AreRelocsRela); |
| return llvm::makeArrayRef(static_cast<const Elf_Rela *>(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<ELFT> *Repl; |
| |
| // Returns the size of this section (even if this is a common or BSS.) |
| size_t getSize() const; |
| |
| ObjectFile<ELFT> *getFile() const { return File; } |
| llvm::object::ELFFile<ELFT> getObj() const { return File->getObj(); } |
| uintX_t getOffset(const DefinedRegular<ELFT> &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 ELFT> class MergeInputSection : public InputSectionBase<ELFT> { |
| 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, |
| 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<SectionPiece> 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<uint8_t> A, size_t Size); |
| void splitNonStrings(ArrayRef<uint8_t> A, size_t Size); |
| |
| std::vector<uint32_t> Hashes; |
| |
| mutable llvm::DenseMap<uintX_t, uintX_t> OffsetMap; |
| mutable std::once_flag InitOffsetMap; |
| |
| llvm::DenseSet<uintX_t> 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<uint8_t> data() { return {ID->Data.data() + this->InputOff, Size}; } |
| unsigned FirstRelocation; |
| }; |
| |
| // This corresponds to a .eh_frame section of an input file. |
| template <class ELFT> class EhInputSection : public InputSectionBase<ELFT> { |
| public: |
| typedef typename ELFT::Shdr Elf_Shdr; |
| typedef typename ELFT::uint uintX_t; |
| EhInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name); |
| static bool classof(const InputSectionData *S); |
| void split(); |
| template <class RelTy> void split(ArrayRef<RelTy> Rels); |
| |
| // Splittable sections are handled as a sequence of data |
| // rather than a single large blob of data. |
| std::vector<EhSectionPiece> Pieces; |
| }; |
| |
| // This corresponds to a non SHF_MERGE section of an input file. |
| template <class ELFT> class InputSection : public InputSectionBase<ELFT> { |
| typedef InputSectionBase<ELFT> 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<uint8_t> Data, StringRef Name, |
| Kind K = InputSectionData::Regular); |
| InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name); |
| |
| static InputSection<ELFT> 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<ELFT> *DependentSection = nullptr; |
| |
| static bool classof(const InputSectionData *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); |
| |
| // Used by ICF. |
| uint32_t Class[2] = {0, 0}; |
| |
| // Called by ICF to merge two input sections. |
| void replace(InputSection<ELFT> *Other); |
| |
| private: |
| template <class RelTy> |
| void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); |
| |
| llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks; |
| }; |
| |
| template <class ELFT> InputSection<ELFT> InputSection<ELFT>::Discarded; |
| } // namespace elf |
| |
| template <class ELFT> std::string toString(const elf::InputSectionBase<ELFT> *); |
| } // namespace lld |
| |
| #endif |