summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorJeremie Courreges-Anglas <jca@cvs.openbsd.org>2024-02-07 20:54:21 +0000
committerJeremie Courreges-Anglas <jca@cvs.openbsd.org>2024-02-07 20:54:21 +0000
commitfa59080cc0803611066efff954018dc1a7b00d4c (patch)
tree19ca58652059dee4fd02f08b6c800ddaecf65737 /gnu
parent1341afb186d2d1e62d8669b2f9de31a9acbb4e42 (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.cpp6
-rw-r--r--gnu/llvm/lld/ELF/InputSection.h256
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