diff options
Diffstat (limited to 'ELF/InputSection.h')
-rw-r--r-- | ELF/InputSection.h | 199 |
1 files changed, 106 insertions, 93 deletions
diff --git a/ELF/InputSection.h b/ELF/InputSection.h index d262b589219a..dfd78a8fb458 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -13,7 +13,7 @@ #include "Config.h" #include "Relocations.h" #include "Thunks.h" -#include "lld/Core/LLVM.h" +#include "lld/Common/LLVM.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" @@ -24,15 +24,13 @@ namespace lld { namespace elf { -class DefinedCommon; -class SymbolBody; +class Symbol; struct SectionPiece; -class DefinedRegular; +class Defined; class SyntheticSection; -template <class ELFT> class EhFrameSection; class MergeSyntheticSection; -template <class ELFT> class ObjectFile; +template <class ELFT> class ObjFile; class OutputSection; // This is the base class of all sections that lld handles. Some are sections in @@ -47,6 +45,13 @@ public: StringRef Name; + // 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. + SectionBase *Repl; + unsigned SectionKind : 3; // The next two bit fields are only used by InputSectionBase, but we @@ -54,12 +59,12 @@ public: // The garbage collector sets sections' Live bits. // If GC is disabled, all sections are considered live by default. - unsigned Live : 1; // for garbage collection - unsigned Assigned : 1; // for linker script + unsigned Live : 1; - uint32_t Alignment; + unsigned Bss : 1; // These corresponds to the fields in Elf_Shdr. + uint32_t Alignment; uint64_t Flags; uint64_t Entsize; uint32_t Type; @@ -75,45 +80,20 @@ public: // section. uint64_t getOffset(uint64_t Offset) const; - uint64_t getOffset(const DefinedRegular &Sym) const; - protected: SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) - : Name(Name), SectionKind(SectionKind), Alignment(Alignment), - Flags(Flags), Entsize(Entsize), Type(Type), Link(Link), Info(Info) { - Live = false; - Assigned = false; - } + : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), + Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize), + Type(Type), Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { public: - static bool classof(const SectionBase *S); - - // The file this section is from. - InputFile *File; - - ArrayRef<uint8_t> Data; - uint64_t getOffsetInFile() const; - - static InputSectionBase Discarded; - - InputSectionBase() - : SectionBase(Regular, "", /*Flags*/ 0, /*Entsize*/ 0, /*Alignment*/ 0, - /*Type*/ 0, - /*Info*/ 0, /*Link*/ 0), - Repl(this) { - Live = false; - Assigned = false; - NumRelocations = 0; - AreRelocsRela = false; - } - template <class ELFT> - InputSectionBase(ObjectFile<ELFT> *File, const typename ELFT::Shdr *Header, + InputSectionBase(ObjFile<ELFT> *File, const typename ELFT::Shdr *Header, StringRef Name, Kind SectionKind); InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, @@ -121,6 +101,33 @@ public: uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind SectionKind); + static bool classof(const SectionBase *S) { return S->kind() != Output; } + + // The file which contains this section. It's dynamic type is always + // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as + // its static type. + InputFile *File; + + template <class ELFT> ObjFile<ELFT> *getFile() const { + return cast_or_null<ObjFile<ELFT>>(File); + } + + ArrayRef<uint8_t> Data; + uint64_t getOffsetInFile() const; + + // True if this section has already been placed to a linker script + // output section. This is needed because, in a linker script, you + // can refer to the same section more than once. For example, in + // the following linker script, + // + // .foo : { *(.text) } + // .bar : { *(.text) } + // + // .foo takes all .text sections, and .bar becomes empty. To achieve + // this, we need to memorize whether a section has been placed or + // not for each input section. + bool Assigned = false; + // Input sections are part of an output section. Special sections // like .eh_frame and merge sections are first combined into a // synthetic section that is then added to an output section. In all @@ -131,12 +138,14 @@ public: const void *FirstRelocation = nullptr; unsigned NumRelocations : 31; unsigned AreRelocsRela : 1; + template <class ELFT> ArrayRef<typename ELFT::Rel> rels() const { assert(!AreRelocsRela); return llvm::makeArrayRef( static_cast<const typename ELFT::Rel *>(FirstRelocation), NumRelocations); } + template <class ELFT> ArrayRef<typename ELFT::Rela> relas() const { assert(AreRelocsRela); return llvm::makeArrayRef( @@ -144,38 +153,34 @@ public: 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; - // InputSections that are dependent on us (reverse dependency for GC) - llvm::TinyPtrVector<InputSectionBase *> DependentSections; + llvm::TinyPtrVector<InputSection *> DependentSections; // Returns the size of this section (even if this is a common or BSS.) size_t getSize() const; - template <class ELFT> ObjectFile<ELFT> *getFile() const; - - template <class ELFT> llvm::object::ELFFile<ELFT> getObj() const { - return getFile<ELFT>()->getObj(); - } - InputSection *getLinkOrderDep() const; - void uncompress(); + // Compilers emit zlib-compressed debug sections if the -gz option + // is given. This function checks if this section is compressed, and + // if so, decompress in memory. + void maybeUncompress(); // Returns a source location string. Used to construct an error message. template <class ELFT> std::string getLocation(uint64_t Offset); - template <class ELFT> std::string getSrcMsg(uint64_t Offset); - template <class ELFT> std::string getObjMsg(uint64_t Offset); + template <class ELFT> + std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); + std::string getObjMsg(uint64_t Offset); + // Each section knows how to relocate itself. These functions apply + // relocations, assuming that Buf points to this section's copy in + // the mmap'ed output buffer. template <class ELFT> void relocate(uint8_t *Buf, uint8_t *BufEnd); void relocateAlloc(uint8_t *Buf, uint8_t *BufEnd); - template <class ELFT> void relocateNonAlloc(uint8_t *Buf, uint8_t *BufEnd); + // The native ELF reloc data type is not very convenient to handle. + // So we convert ELF reloc records to our own records in Relocations.cpp. + // This vector contains such "cooked" relocations. std::vector<Relocation> Relocations; template <typename T> llvm::ArrayRef<T> getDataAs() const { @@ -183,36 +188,43 @@ public: assert(S % sizeof(T) == 0); return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T)); } + +private: + // A pointer that owns uncompressed data if a section is compressed by zlib. + // Since the feature is not used often, this is usually a nullptr. + std::unique_ptr<char[]> UncompressBuf; }; // 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. +// be found by looking at the next one). 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; + SectionPiece(size_t Off, uint32_t Hash, bool Live) + : InputOff(Off), Hash(Hash), OutputOff(-1), + Live(Live || !Config->GcSections) {} + + uint32_t InputOff; + uint32_t Hash; + int64_t OutputOff : 63; + uint64_t Live : 1; }; -static_assert(sizeof(SectionPiece) == 2 * sizeof(size_t), - "SectionPiece is too big"); + +static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); // This corresponds to a SHF_MERGE section of an input file. class MergeInputSection : public InputSectionBase { public: template <class ELFT> - MergeInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + MergeInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); - static bool classof(const SectionBase *S); + static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); // Mark the piece at a given offset live. Used by GC. void markLiveAt(uint64_t Offset) { - assert(this->Flags & llvm::ELF::SHF_ALLOC); - LiveOffsets.insert(Offset); + if (this->Flags & llvm::ELF::SHF_ALLOC) + LiveOffsets.insert(Offset); } // Translate an offset in the input section to an offset @@ -228,14 +240,9 @@ public: 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]}; + size_t End = + (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff; + return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash}; } // Returns the SectionPiece at a given input section offset. @@ -248,24 +255,23 @@ 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<uint64_t, uint64_t> OffsetMap; + mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap; mutable llvm::once_flag InitOffsetMap; llvm::DenseSet<uint64_t> LiveOffsets; }; -struct EhSectionPiece : public SectionPiece { - EhSectionPiece(size_t Off, InputSectionBase *ID, uint32_t Size, +struct EhSectionPiece { + EhSectionPiece(size_t Off, InputSectionBase *Sec, uint32_t Size, unsigned FirstRelocation) - : SectionPiece(Off, false), ID(ID), Size(Size), - FirstRelocation(FirstRelocation) {} - InputSectionBase *ID; - uint32_t Size; - uint32_t size() const { return Size; } + : InputOff(Off), Sec(Sec), Size(Size), FirstRelocation(FirstRelocation) {} - ArrayRef<uint8_t> data() { return {ID->Data.data() + this->InputOff, Size}; } + ArrayRef<uint8_t> data() { return {Sec->Data.data() + this->InputOff, Size}; } + + size_t InputOff; + ssize_t OutputOff = -1; + InputSectionBase *Sec; + uint32_t Size; unsigned FirstRelocation; }; @@ -273,9 +279,9 @@ struct EhSectionPiece : public SectionPiece { class EhInputSection : public InputSectionBase { public: template <class ELFT> - EhInputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + EhInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); - static bool classof(const SectionBase *S); + static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } template <class ELFT> void split(); template <class ELFT, class RelTy> void split(ArrayRef<RelTy> Rels); @@ -295,7 +301,7 @@ public: InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular); template <class ELFT> - InputSection(ObjectFile<ELFT> *F, const typename ELFT::Shdr *Header, + InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to @@ -304,8 +310,10 @@ public: OutputSection *getParent() const; - // The offset from beginning of the output sections this section was assigned - // to. The writer sets a value. + // This variable has two usages. Initially, it represents an index in the + // OutputSection's InputSection list, and is used when ordering SHF_LINK_ORDER + // sections. After assignAddresses is called, it represents the offset from + // the beginning of the output section this section was assigned to. uint64_t OutSecOff = 0; static bool classof(const SectionBase *S); @@ -321,6 +329,8 @@ public: // Called by ICF to merge two input sections. void replace(InputSection *Other); + static InputSection Discarded; + private: template <class ELFT, class RelTy> void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); @@ -331,6 +341,9 @@ private: // The list of all input sections. extern std::vector<InputSectionBase *> InputSections; +// Builds section order for handling --symbol-ordering-file. +llvm::DenseMap<SectionBase *, int> buildSectionOrder(); + } // namespace elf std::string toString(const elf::InputSectionBase *); |