| //===- InputSection.h -------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLD_ELF_INPUT_SECTION_H |
| #define LLD_ELF_INPUT_SECTION_H |
| |
| #include "Config.h" |
| #include "Relocations.h" |
| #include "lld/Common/CommonLinkerContext.h" |
| #include "lld/Common/LLVM.h" |
| #include "lld/Common/Memory.h" |
| #include "llvm/ADT/CachedHashString.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/TinyPtrVector.h" |
| #include "llvm/Object/ELF.h" |
| #include "llvm/Support/Compiler.h" |
| |
| namespace lld { |
| namespace elf { |
| |
| class InputFile; |
| class Symbol; |
| |
| class Defined; |
| struct Partition; |
| class SyntheticSection; |
| template <class ELFT> class ObjFile; |
| class OutputSection; |
| |
| LLVM_LIBRARY_VISIBILITY extern std::vector<Partition> partitions; |
| |
| // Returned by InputSectionBase::relsOrRelas. At most one member is empty. |
| template <class ELFT> struct RelsOrRelas { |
| Relocs<typename ELFT::Rel> rels; |
| Relocs<typename ELFT::Rela> relas; |
| Relocs<typename ELFT::Crel> crels; |
| bool areRelocsRel() const { return rels.size(); } |
| bool areRelocsCrel() const { return crels.size(); } |
| }; |
| |
| #define invokeOnRelocs(sec, f, ...) \ |
| { \ |
| const RelsOrRelas<ELFT> rs = (sec).template relsOrRelas<ELFT>(); \ |
| if (rs.areRelocsCrel()) \ |
| f(__VA_ARGS__, rs.crels); \ |
| else if (rs.areRelocsRel()) \ |
| f(__VA_ARGS__, rs.rels); \ |
| else \ |
| f(__VA_ARGS__, rs.relas); \ |
| } |
| |
| // This is the base class of all sections that lld handles. Some are sections in |
| // input files, some are sections in the produced output file and some exist |
| // just as a convenience for implementing special ways of combining some |
| // sections. |
| class SectionBase { |
| public: |
| enum Kind { Regular, Synthetic, Spill, EHFrame, Merge, Output, Class }; |
| |
| Kind kind() const { return (Kind)sectionKind; } |
| |
| LLVM_PREFERRED_TYPE(Kind) |
| uint8_t sectionKind : 3; |
| |
| // The next two bit fields are only used by InputSectionBase, but we |
| // put them here so the struct packs better. |
| |
| LLVM_PREFERRED_TYPE(bool) |
| uint8_t bss : 1; |
| |
| // Set for sections that should not be folded by ICF. |
| LLVM_PREFERRED_TYPE(bool) |
| uint8_t keepUnique : 1; |
| |
| uint8_t partition = 1; |
| uint32_t type; |
| StringRef name; |
| |
| // The 1-indexed partition that this section is assigned to by the garbage |
| // collector, or 0 if this section is dead. Normally there is only one |
| // partition, so this will either be 0 or 1. |
| elf::Partition &getPartition() const; |
| |
| // These corresponds to the fields in Elf_Shdr. |
| uint64_t flags; |
| uint32_t addralign; |
| uint32_t entsize; |
| uint32_t link; |
| uint32_t info; |
| |
| OutputSection *getOutputSection(); |
| const OutputSection *getOutputSection() const { |
| return const_cast<SectionBase *>(this)->getOutputSection(); |
| } |
| |
| // Translate an offset in the input section to an offset in the output |
| // section. |
| uint64_t getOffset(uint64_t offset) const; |
| |
| uint64_t getVA(uint64_t offset = 0) const; |
| |
| bool isLive() const { return partition != 0; } |
| void markLive() { partition = 1; } |
| void markDead() { partition = 0; } |
| |
| protected: |
| constexpr SectionBase(Kind sectionKind, StringRef name, uint64_t flags, |
| uint32_t entsize, uint32_t addralign, uint32_t type, |
| uint32_t info, uint32_t link) |
| : sectionKind(sectionKind), bss(false), keepUnique(false), type(type), |
| name(name), flags(flags), addralign(addralign), entsize(entsize), |
| link(link), info(info) {} |
| }; |
| |
| struct SymbolAnchor { |
| uint64_t offset; |
| Defined *d; |
| bool end; // true for the anchor of st_value+st_size |
| }; |
| |
| struct RelaxAux { |
| // This records symbol start and end offsets which will be adjusted according |
| // to the nearest relocDeltas element. |
| SmallVector<SymbolAnchor, 0> anchors; |
| // For relocations[i], the actual offset is |
| // r_offset - (i ? relocDeltas[i-1] : 0). |
| std::unique_ptr<uint32_t[]> relocDeltas; |
| // For relocations[i], the actual type is relocTypes[i]. |
| std::unique_ptr<RelType[]> relocTypes; |
| SmallVector<uint32_t, 0> writes; |
| }; |
| |
| // This corresponds to a section of an input file. |
| class InputSectionBase : public SectionBase { |
| public: |
| template <class ELFT> |
| InputSectionBase(ObjFile<ELFT> &file, const typename ELFT::Shdr &header, |
| StringRef name, Kind sectionKind); |
| |
| InputSectionBase(InputFile *file, uint64_t flags, uint32_t type, |
| uint64_t entsize, uint32_t link, uint32_t info, |
| uint32_t addralign, ArrayRef<uint8_t> data, StringRef name, |
| Kind sectionKind); |
| |
| static bool classof(const SectionBase *s) { |
| return s->kind() != Output && s->kind() != Class; |
| } |
| |
| // The file which contains this section. Its dynamic type is usually |
| // ObjFile<ELFT>, but may be an InputFile of InternalKind (for a synthetic |
| // section). |
| InputFile *file; |
| |
| // 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 |
| // cases this points one level up. |
| SectionBase *parent = nullptr; |
| |
| // Section index of the relocation section if exists. |
| uint32_t relSecIdx = 0; |
| |
| // Getter when the dynamic type is ObjFile<ELFT>. |
| template <class ELFT> ObjFile<ELFT> *getFile() const { |
| return cast<ObjFile<ELFT>>(file); |
| } |
| |
| // Used by --optimize-bb-jumps and RISC-V linker relaxation temporarily to |
| // indicate the number of bytes which is not counted in the size. This should |
| // be reset to zero after uses. |
| uint32_t bytesDropped = 0; |
| |
| mutable bool compressed = false; |
| |
| // Whether the section needs to be padded with a NOP filler due to |
| // deleteFallThruJmpInsn. |
| bool nopFiller = false; |
| |
| void drop_back(unsigned num) { |
| assert(bytesDropped + num < 256); |
| bytesDropped += num; |
| } |
| |
| void push_back(uint64_t num) { |
| assert(bytesDropped >= num); |
| bytesDropped -= num; |
| } |
| |
| mutable const uint8_t *content_; |
| uint64_t size; |
| |
| void trim() { |
| if (bytesDropped) { |
| size -= bytesDropped; |
| bytesDropped = 0; |
| } |
| } |
| |
| ArrayRef<uint8_t> content() const { |
| return ArrayRef<uint8_t>(content_, size); |
| } |
| ArrayRef<uint8_t> contentMaybeDecompress() const { |
| if (compressed) |
| decompress(); |
| return content(); |
| } |
| |
| // The next member in the section group if this section is in a group. This is |
| // used by --gc-sections. |
| InputSectionBase *nextInSectionGroup = nullptr; |
| |
| template <class ELFT> |
| RelsOrRelas<ELFT> relsOrRelas(bool supportsCrel = true) const; |
| |
| // InputSections that are dependent on us (reverse dependency for GC) |
| llvm::TinyPtrVector<InputSection *> dependentSections; |
| |
| // Returns the size of this section (even if this is a common or BSS.) |
| size_t getSize() const; |
| |
| InputSection *getLinkOrderDep() const; |
| |
| // Get a symbol that encloses this offset from within the section. If type is |
| // not zero, return a symbol with the specified type. |
| Defined *getEnclosingSymbol(uint64_t offset, uint8_t type = 0) const; |
| Defined *getEnclosingFunction(uint64_t offset) const { |
| return getEnclosingSymbol(offset, llvm::ELF::STT_FUNC); |
| } |
| |
| // Returns a source location string. Used to construct an error message. |
| std::string getLocation(uint64_t offset) const; |
| std::string getSrcMsg(const Symbol &sym, uint64_t offset) const; |
| std::string getObjMsg(uint64_t offset) const; |
| |
| // 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); |
| static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, |
| int64_t A, uint64_t P, const Symbol &Sym, |
| RelExpr Expr); |
| |
| // 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. |
| SmallVector<Relocation, 0> relocations; |
| |
| void addReloc(const Relocation &r) { relocations.push_back(r); } |
| MutableArrayRef<Relocation> relocs() { return relocations; } |
| ArrayRef<Relocation> relocs() const { return relocations; } |
| |
| union { |
| // These are modifiers to jump instructions that are necessary when basic |
| // block sections are enabled. Basic block sections creates opportunities |
| // to relax jump instructions at basic block boundaries after reordering the |
| // basic blocks. |
| JumpInstrMod *jumpInstrMod = nullptr; |
| |
| // Auxiliary information for RISC-V and LoongArch linker relaxation. |
| // They do not use jumpInstrMod. |
| RelaxAux *relaxAux; |
| |
| // The compressed content size when `compressed` is true. |
| size_t compressedSize; |
| }; |
| |
| // A function compiled with -fsplit-stack calling a function |
| // compiled without -fsplit-stack needs its prologue adjusted. Find |
| // such functions and adjust their prologues. This is very similar |
| // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more |
| // information. |
| template <typename ELFT> |
| void adjustSplitStackFunctionPrologues(uint8_t *buf, uint8_t *end); |
| |
| |
| template <typename T> llvm::ArrayRef<T> getDataAs() const { |
| size_t s = content().size(); |
| assert(s % sizeof(T) == 0); |
| return llvm::ArrayRef<T>((const T *)content().data(), s / sizeof(T)); |
| } |
| |
| protected: |
| template <typename ELFT> |
| void parseCompressedHeader(); |
| void decompress() const; |
| }; |
| |
| // 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). |
| struct SectionPiece { |
| SectionPiece() = default; |
| SectionPiece(size_t off, uint32_t hash, bool live) |
| : inputOff(off), live(live), hash(hash >> 1) {} |
| |
| uint32_t inputOff; |
| LLVM_PREFERRED_TYPE(bool) |
| uint32_t live : 1; |
| uint32_t hash : 31; |
| uint64_t outputOff = 0; |
| }; |
| |
| 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(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, |
| StringRef name); |
| MergeInputSection(uint64_t flags, uint32_t type, uint64_t entsize, |
| ArrayRef<uint8_t> data, StringRef name); |
| |
| static bool classof(const SectionBase *s) { return s->kind() == Merge; } |
| void splitIntoPieces(); |
| |
| // Translate an offset in the input section to an offset in the parent |
| // MergeSyntheticSection. |
| uint64_t getParentOffset(uint64_t offset) const; |
| |
| // Splittable sections are handled as a sequence of data |
| // rather than a single large blob of data. |
| SmallVector<SectionPiece, 0> 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 = |
| (pieces.size() - 1 == i) ? content().size() : pieces[i + 1].inputOff; |
| return {toStringRef(content().slice(begin, end - begin)), pieces[i].hash}; |
| } |
| |
| // Returns the SectionPiece at a given input section offset. |
| SectionPiece &getSectionPiece(uint64_t offset); |
| const SectionPiece &getSectionPiece(uint64_t offset) const { |
| return const_cast<MergeInputSection *>(this)->getSectionPiece(offset); |
| } |
| |
| SyntheticSection *getParent() const { |
| return cast_or_null<SyntheticSection>(parent); |
| } |
| |
| private: |
| void splitStrings(StringRef s, size_t size); |
| void splitNonStrings(ArrayRef<uint8_t> a, size_t size); |
| }; |
| |
| struct EhSectionPiece { |
| EhSectionPiece(size_t off, InputSectionBase *sec, uint32_t size, |
| unsigned firstRelocation) |
| : inputOff(off), sec(sec), size(size), firstRelocation(firstRelocation) {} |
| |
| ArrayRef<uint8_t> data() const { |
| return {sec->content().data() + this->inputOff, size}; |
| } |
| |
| size_t inputOff; |
| ssize_t outputOff = -1; |
| InputSectionBase *sec; |
| uint32_t size; |
| unsigned firstRelocation; |
| }; |
| |
| // This corresponds to a .eh_frame section of an input file. |
| class EhInputSection : public InputSectionBase { |
| public: |
| template <class ELFT> |
| EhInputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, |
| StringRef name); |
| 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); |
| |
| // Splittable sections are handled as a sequence of data |
| // rather than a single large blob of data. |
| SmallVector<EhSectionPiece, 0> cies, fdes; |
| |
| SyntheticSection *getParent() const; |
| uint64_t getParentOffset(uint64_t offset) const; |
| }; |
| |
| // This is a section that is added directly to an output section |
| // instead of needing special combination via a synthetic section. This |
| // includes all input sections with the exceptions of SHF_MERGE and |
| // .eh_frame. It also includes the synthetic sections themselves. |
| class InputSection : public InputSectionBase { |
| public: |
| InputSection(InputFile *f, uint64_t flags, uint32_t type, uint32_t addralign, |
| ArrayRef<uint8_t> data, StringRef name, Kind k = Regular); |
| template <class ELFT> |
| InputSection(ObjFile<ELFT> &f, const typename ELFT::Shdr &header, |
| StringRef name); |
| |
| static bool classof(const SectionBase *s) { |
| return s->kind() == SectionBase::Regular || |
| s->kind() == SectionBase::Synthetic || |
| s->kind() == SectionBase::Spill; |
| } |
| |
| // Write this section to a mmap'ed file, assuming Buf is pointing to |
| // beginning of the output section. |
| template <class ELFT> void writeTo(uint8_t *buf); |
| |
| OutputSection *getParent() const { |
| return reinterpret_cast<OutputSection *>(parent); |
| } |
| |
| // 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; |
| |
| InputSectionBase *getRelocatedSection() const; |
| |
| template <class ELFT, class RelTy> |
| void relocateNonAlloc(uint8_t *buf, Relocs<RelTy> rels); |
| |
| // Points to the canonical section. If ICF folds two sections, repl pointer of |
| // one section points to the other. |
| InputSection *repl = this; |
| |
| // Used by ICF. |
| uint32_t eqClass[2] = {0, 0}; |
| |
| // 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); |
| |
| template <class ELFT, class RelTy, class RelIt> |
| void copyRelocations(uint8_t *buf, llvm::iterator_range<RelIt> rels); |
| |
| template <class ELFT> void copyShtGroup(uint8_t *buf); |
| }; |
| |
| // A marker for a potential spill location for another input section. This |
| // broadly acts as if it were the original section until address assignment. |
| // Then it is either replaced with the real input section or removed. |
| class PotentialSpillSection : public InputSection { |
| public: |
| // The containing input section description; used to quickly replace this stub |
| // with the actual section. |
| InputSectionDescription *isd; |
| |
| // Next potential spill location for the same source input section. |
| PotentialSpillSection *next = nullptr; |
| |
| PotentialSpillSection(const InputSectionBase &source, |
| InputSectionDescription &isd); |
| |
| static bool classof(const SectionBase *sec) { |
| return sec->kind() == InputSectionBase::Spill; |
| } |
| }; |
| |
| static_assert(sizeof(InputSection) <= 160, "InputSection is too big"); |
| |
| class SyntheticSection : public InputSection { |
| public: |
| SyntheticSection(uint64_t flags, uint32_t type, uint32_t addralign, |
| StringRef name) |
| : InputSection(ctx.internalFile, flags, type, addralign, {}, name, |
| InputSectionBase::Synthetic) {} |
| |
| virtual ~SyntheticSection() = default; |
| virtual size_t getSize() const = 0; |
| virtual bool updateAllocSize() { return false; } |
| // If the section has the SHF_ALLOC flag and the size may be changed if |
| // thunks are added, update the section size. |
| virtual bool isNeeded() const { return true; } |
| virtual void finalizeContents() {} |
| virtual void writeTo(uint8_t *buf) = 0; |
| |
| static bool classof(const SectionBase *sec) { |
| return sec->kind() == InputSectionBase::Synthetic; |
| } |
| }; |
| |
| inline bool isStaticRelSecType(uint32_t type) { |
| return type == llvm::ELF::SHT_RELA || type == llvm::ELF::SHT_CREL || |
| type == llvm::ELF::SHT_REL; |
| } |
| |
| inline bool isDebugSection(const InputSectionBase &sec) { |
| return (sec.flags & llvm::ELF::SHF_ALLOC) == 0 && |
| sec.name.starts_with(".debug"); |
| } |
| } // namespace elf |
| |
| std::string toString(const elf::InputSectionBase *); |
| } // namespace lld |
| |
| #endif |