#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;
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); \
}
class SectionBase {
public:
enum Kind { Regular, Synthetic, Spill, EHFrame, Merge, Output };
Kind kind() const { return (Kind)sectionKind; }
LLVM_PREFERRED_TYPE(Kind)
uint8_t sectionKind : 3;
LLVM_PREFERRED_TYPE(bool)
uint8_t bss : 1;
LLVM_PREFERRED_TYPE(bool)
uint8_t keepUnique : 1;
uint8_t partition = 1;
uint32_t type;
StringRef name;
elf::Partition &getPartition() const;
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();
}
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;
};
struct RelaxAux {
SmallVector<SymbolAnchor, 0> anchors;
std::unique_ptr<uint32_t[]> relocDeltas;
std::unique_ptr<RelType[]> relocTypes;
SmallVector<uint32_t, 0> writes;
};
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; }
InputFile *file;
SectionBase *parent = nullptr;
uint32_t relSecIdx = 0;
template <class ELFT> ObjFile<ELFT> *getFile() const {
return cast<ObjFile<ELFT>>(file);
}
uint32_t bytesDropped = 0;
mutable bool compressed = false;
bool decodedCrel = false;
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();
}
InputSectionBase *nextInSectionGroup = nullptr;
template <class ELFT>
RelsOrRelas<ELFT> relsOrRelas(bool supportsCrel = true) const;
llvm::TinyPtrVector<InputSection *> dependentSections;
size_t getSize() const;
InputSection *getLinkOrderDep() const;
Defined *getEnclosingSymbol(uint64_t offset, uint8_t type = 0) const;
Defined *getEnclosingFunction(uint64_t offset) const {
return getEnclosingSymbol(offset, llvm::ELF::STT_FUNC);
}
std::string getLocation(uint64_t offset) const;
std::string getSrcMsg(const Symbol &sym, uint64_t offset) const;
std::string getObjMsg(uint64_t offset) const;
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);
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 {
JumpInstrMod *jumpInstrMod = nullptr;
RelaxAux *relaxAux;
size_t compressedSize;
};
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;
};
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");
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();
uint64_t getParentOffset(uint64_t offset) const;
SmallVector<SectionPiece, 0> pieces;
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};
}
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;
};
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);
SmallVector<EhSectionPiece, 0> cies, fdes;
SyntheticSection *getParent() const;
uint64_t getParentOffset(uint64_t offset) const;
};
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;
}
template <class ELFT> void writeTo(uint8_t *buf);
OutputSection *getParent() const {
return reinterpret_cast<OutputSection *>(parent);
}
uint64_t outSecOff = 0;
InputSectionBase *getRelocatedSection() const;
template <class ELFT, class RelTy>
void relocateNonAlloc(uint8_t *buf, Relocs<RelTy> rels);
InputSection *repl = this;
uint32_t eqClass[2] = {0, 0};
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);
};
class PotentialSpillSection : public InputSection {
public:
InputSectionDescription *isd;
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; }
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");
}
extern llvm::DenseSet<std::pair<const Symbol *, uint64_t>> ppc64noTocRelax;
}
std::string toString(const elf::InputSectionBase *);
}
#endif