diff options
author | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2024-02-07 20:54:21 +0000 |
---|---|---|
committer | Jeremie Courreges-Anglas <jca@cvs.openbsd.org> | 2024-02-07 20:54:21 +0000 |
commit | fa59080cc0803611066efff954018dc1a7b00d4c (patch) | |
tree | 19ca58652059dee4fd02f08b6c800ddaecf65737 /gnu | |
parent | 1341afb186d2d1e62d8669b2f9de31a9acbb4e42 (diff) |
riscv64 fix: Handle relaxation reductions of more than 65536 bytes
Upstream commit:
https://github.com/llvm/llvm-project/commit/9d37ea95df1b84cca9b5e954d8964c976a5e303e
Already needed at least by ports/math/hdf5, prerequisite if we want to
enable linker relaxation (clang upstream defaults).
ok kettenis@
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/llvm/lld/ELF/Arch/RISCV.cpp | 6 | ||||
-rw-r--r-- | gnu/llvm/lld/ELF/InputSection.h | 256 |
2 files changed, 168 insertions, 94 deletions
diff --git a/gnu/llvm/lld/ELF/Arch/RISCV.cpp b/gnu/llvm/lld/ELF/Arch/RISCV.cpp index b0864b51779..4811d50adff 100644 --- a/gnu/llvm/lld/ELF/Arch/RISCV.cpp +++ b/gnu/llvm/lld/ELF/Arch/RISCV.cpp @@ -621,7 +621,7 @@ static bool relax(InputSection &sec) { // iteration. DenseMap<const Defined *, uint64_t> valueDelta; ArrayRef<SymbolAnchor> sa = ArrayRef(aux.anchors); - uint32_t delta = 0; + uint64_t delta = 0; for (auto [i, r] : llvm::enumerate(sec.relocs())) { for (; sa.size() && sa[0].offset <= r.offset; sa = sa.slice(1)) if (!sa[0].end) @@ -688,8 +688,8 @@ static bool relax(InputSection &sec) { a.d->value -= delta - valueDelta.find(a.d)->second; } // Inform assignAddresses that the size has changed. - if (!isUInt<16>(delta)) - fatal("section size decrease is too large"); + if (!isUInt<32>(delta)) + fatal("section size decrease is too large: " + Twine(delta)); sec.bytesDropped = delta; return changed; } diff --git a/gnu/llvm/lld/ELF/InputSection.h b/gnu/llvm/lld/ELF/InputSection.h index 3c42af7db7b..143384b3ba7 100644 --- a/gnu/llvm/lld/ELF/InputSection.h +++ b/gnu/llvm/lld/ELF/InputSection.h @@ -9,29 +9,36 @@ #ifndef LLD_ELF_INPUT_SECTION_H #define LLD_ELF_INPUT_SECTION_H -#include "Config.h" #include "Relocations.h" -#include "Thunks.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/TinyPtrVector.h" #include "llvm/Object/ELF.h" +#include "llvm/Support/Compiler.h" namespace lld { namespace elf { +class InputFile; class Symbol; -struct SectionPiece; class Defined; struct Partition; class SyntheticSection; -class MergeSyntheticSection; template <class ELFT> class ObjFile; class OutputSection; -extern std::vector<Partition> partitions; +LLVM_LIBRARY_VISIBILITY extern std::vector<Partition> partitions; + +// Returned by InputSectionBase::relsOrRelas. At least one member is empty. +template <class ELFT> struct RelsOrRelas { + ArrayRef<typename ELFT::Rel> rels; + ArrayRef<typename ELFT::Rela> relas; + bool areRelocsRel() const { return rels.size(); } +}; // 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 @@ -39,40 +46,33 @@ extern std::vector<Partition> partitions; // sections. class SectionBase { public: - enum Kind { Regular, EHFrame, Merge, Synthetic, Output }; + enum Kind { Regular, Synthetic, EHFrame, Merge, Output }; Kind kind() const { return (Kind)sectionKind; } - 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; + uint8_t sectionKind : 3; // The next two bit fields are only used by InputSectionBase, but we // put them here so the struct packs better. - unsigned bss : 1; + uint8_t bss : 1; // Set for sections that should not be folded by ICF. - unsigned keepUnique : 1; + 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. - uint8_t partition; elf::Partition &getPartition() const; // These corresponds to the fields in Elf_Shdr. - uint32_t alignment; uint64_t flags; - uint64_t entsize; - uint32_t type; + uint32_t addralign; + uint32_t entsize; uint32_t link; uint32_t info; @@ -92,14 +92,16 @@ public: void markDead() { partition = 0; } 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), repl(this), sectionKind(sectionKind), bss(false), - keepUnique(false), partition(0), alignment(alignment), flags(flags), - entsize(entsize), type(type), link(link), info(info) {} + 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 RISCVRelaxAux; + // This corresponds to a section of an input file. class InputSectionBase : public SectionBase { public: @@ -109,56 +111,74 @@ public: InputSectionBase(InputFile *file, uint64_t flags, uint32_t type, uint64_t entsize, uint32_t link, uint32_t info, - uint32_t alignment, ArrayRef<uint8_t> data, StringRef name, + uint32_t addralign, ArrayRef<uint8_t> data, StringRef name, Kind sectionKind); static bool classof(const SectionBase *s) { return s->kind() != Output; } - // Relocations that refer to this section. - unsigned numRelocations : 31; - unsigned areRelocsRela : 1; - const void *firstRelocation = nullptr; - // The file which contains this section. Its dynamic type is always // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as // its static type. 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; + template <class ELFT> ObjFile<ELFT> *getFile() const { return cast_or_null<ObjFile<ELFT>>(file); } - ArrayRef<uint8_t> data() const { - if (uncompressedSize >= 0) - uncompress(); - return rawData; + // 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; } - uint64_t getOffsetInFile() const; + void push_back(uint64_t num) { + assert(bytesDropped >= num); + bytesDropped -= num; + } - // 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; + 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> 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( - static_cast<const typename ELFT::Rela *>(firstRelocation), - numRelocations); - } + template <class ELFT> RelsOrRelas<ELFT> relsOrRelas() const; // InputSections that are dependent on us (reverse dependency for GC) llvm::TinyPtrVector<InputSection *> dependentSections; @@ -170,11 +190,10 @@ public: // Get the function symbol that encloses this offset from within the // section. - template <class ELFT> Defined *getEnclosingFunction(uint64_t offset); // Returns a source location string. Used to construct an error message. - template <class ELFT> std::string getLocation(uint64_t offset); + std::string getLocation(uint64_t offset); std::string getSrcMsg(const Symbol &sym, uint64_t offset); std::string getObjMsg(uint64_t offset); @@ -182,12 +201,33 @@ public: // 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); + 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. - std::vector<Relocation> 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 linker relaxation. RISC-V does not use + // jumpInstrMod. + RISCVRelaxAux *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 @@ -199,22 +239,15 @@ public: template <typename T> llvm::ArrayRef<T> getDataAs() const { - size_t s = data().size(); + size_t s = content().size(); assert(s % sizeof(T) == 0); - return llvm::makeArrayRef<T>((const T *)data().data(), s / sizeof(T)); + return llvm::ArrayRef<T>((const T *)content().data(), s / sizeof(T)); } protected: + template <typename ELFT> void parseCompressedHeader(); - void uncompress() const; - - mutable ArrayRef<uint8_t> rawData; - - // This field stores the uncompressed size of the compressed data in rawData, - // or -1 if rawData is not compressed (either because the section wasn't - // compressed in the first place, or because we ended up uncompressing it). - // Since the feature is not used often, this is usually -1. - mutable int64_t uncompressedSize = -1; + void decompress() const; }; // SectionPiece represents a piece of splittable section contents. @@ -222,8 +255,9 @@ protected: // 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 || !config->gcSections), hash(hash >> 1) {} + : inputOff(off), live(live), hash(hash >> 1) {} uint32_t inputOff; uint32_t live : 1; @@ -251,7 +285,7 @@ public: // Splittable sections are handled as a sequence of data // rather than a single large blob of data. - std::vector<SectionPiece> pieces; + 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. @@ -259,20 +293,22 @@ public: llvm::CachedHashStringRef getData(size_t i) const { size_t begin = pieces[i].inputOff; size_t end = - (pieces.size() - 1 == i) ? data().size() : pieces[i + 1].inputOff; - return {toStringRef(data().slice(begin, end - begin)), pieces[i].hash}; + (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 { + SectionPiece &getSectionPiece(uint64_t offset); + const SectionPiece &getSectionPiece(uint64_t offset) const { return const_cast<MergeInputSection *>(this)->getSectionPiece(offset); } - SyntheticSection *getParent() const; + SyntheticSection *getParent() const { + return cast_or_null<SyntheticSection>(parent); + } private: - void splitStrings(ArrayRef<uint8_t> a, size_t size); + void splitStrings(StringRef s, size_t size); void splitNonStrings(ArrayRef<uint8_t> a, size_t size); }; @@ -281,8 +317,8 @@ struct EhSectionPiece { unsigned firstRelocation) : inputOff(off), sec(sec), size(size), firstRelocation(firstRelocation) {} - ArrayRef<uint8_t> data() { - return {sec->data().data() + this->inputOff, size}; + ArrayRef<uint8_t> data() const { + return {sec->content().data() + this->inputOff, size}; } size_t inputOff; @@ -304,9 +340,10 @@ public: // Splittable sections are handled as a sequence of data // rather than a single large blob of data. - std::vector<EhSectionPiece> pieces; + 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 @@ -315,19 +352,24 @@ public: // .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 alignment, + 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; + } + // 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); - uint64_t getOffset(uint64_t offset) const { return outSecOff + offset; } - - OutputSection *getParent() const; + 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 @@ -335,13 +377,15 @@ public: // the beginning of the output section this section was assigned to. uint64_t outSecOff = 0; - static bool classof(const SectionBase *s); - InputSectionBase *getRelocatedSection() const; template <class ELFT, class RelTy> void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef<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}; @@ -357,8 +401,38 @@ private: template <class ELFT> void copyShtGroup(uint8_t *buf); }; -// The list of all input sections. -extern std::vector<InputSectionBase *> inputSections; +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(nullptr, 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 isDebugSection(const InputSectionBase &sec) { + return (sec.flags & llvm::ELF::SHF_ALLOC) == 0 && + sec.name.startswith(".debug"); +} + +// The set of TOC entries (.toc + addend) for which we should not apply +// toc-indirect to toc-relative relaxation. const Symbol * refers to the +// STT_SECTION symbol associated to the .toc input section. +extern llvm::DenseSet<std::pair<const Symbol *, uint64_t>> ppc64noTocRelax; } // namespace elf |