summaryrefslogtreecommitdiff
path: root/ELF/InputSection.h
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/InputSection.h')
-rw-r--r--ELF/InputSection.h206
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