blob: 60c8d57b8db86aa9a8ec98681c208b791e8145ce [file] [log] [blame]
//===- 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