#ifndef LLD_ELF_INPUT_SECTION_H
#define LLD_ELF_INPUT_SECTION_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/TinyPtrVector.h"
#include "llvm/Object/ELF.h"
namespace lld {
namespace elf {
class InputFile;
class Symbol;
class Defined;
struct Partition;
class SyntheticSection;
template <class ELFT> class ObjFile;
class OutputSection;
extern std::vector<Partition> partitions;
template <class ELFT> struct RelsOrRelas {
ArrayRef<typename ELFT::Rel> rels;
ArrayRef<typename ELFT::Rela> relas;
bool areRelocsRel() const { return rels.size(); }
};
class SectionBase {
public:
enum Kind { Regular, Synthetic, EHFrame, Merge, Output };
Kind kind() const { return (Kind)sectionKind; }
StringRef name;
uint8_t sectionKind : 3;
uint8_t bss : 1;
uint8_t keepUnique : 1;
uint8_t partition = 1;
elf::Partition &getPartition() const;
uint32_t alignment;
uint64_t flags;
uint32_t entsize;
uint32_t type;
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 alignment, uint32_t type,
uint32_t info, uint32_t link)
: name(name), sectionKind(sectionKind), bss(false), keepUnique(false),
alignment(alignment), flags(flags), entsize(entsize), type(type),
link(link), info(info) {}
};
struct RISCVRelaxAux;
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 alignment, 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_or_null<ObjFile<ELFT>>(file);
}
uint16_t bytesDropped = 0;
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 ArrayRef<uint8_t> rawData;
void trim() {
if (bytesDropped) {
rawData = rawData.drop_back(bytesDropped);
bytesDropped = 0;
}
}
ArrayRef<uint8_t> data() const {
if (uncompressedSize >= 0)
uncompress();
return rawData;
}
InputSectionBase *nextInSectionGroup = nullptr;
template <class ELFT> RelsOrRelas<ELFT> relsOrRelas() const;
llvm::TinyPtrVector<InputSection *> dependentSections;
size_t getSize() const;
InputSection *getLinkOrderDep() const;
Defined *getEnclosingFunction(uint64_t offset);
std::string getLocation(uint64_t offset);
std::string getSrcMsg(const Symbol &sym, uint64_t offset);
std::string getObjMsg(uint64_t offset);
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);
SmallVector<Relocation, 0> relocations;
union {
JumpInstrMod *jumpInstrMod = nullptr;
RISCVRelaxAux *relaxAux;
};
template <typename ELFT>
void adjustSplitStackFunctionPrologues(uint8_t *buf, uint8_t *end);
template <typename T> llvm::ArrayRef<T> getDataAs() const {
size_t s = rawData.size();
assert(s % sizeof(T) == 0);
return llvm::makeArrayRef<T>((const T *)rawData.data(), s / sizeof(T));
}
protected:
template <typename ELFT>
void parseCompressedHeader();
void uncompress() const;
mutable int64_t uncompressedSize = -1;
};
struct SectionPiece {
SectionPiece() = default;
SectionPiece(size_t off, uint32_t hash, bool live)
: inputOff(off), live(live), hash(hash >> 1) {}
uint32_t inputOff;
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) ? rawData.size() : pieces[i + 1].inputOff;
return {toStringRef(rawData.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;
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->rawData.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> pieces;
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 alignment,
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;
}
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, llvm::ArrayRef<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, llvm::ArrayRef<RelTy> rels);
template <class ELFT> void copyShtGroup(uint8_t *buf);
};
static_assert(sizeof(InputSection) <= 160, "InputSection is too big");
inline bool isDebugSection(const InputSectionBase &sec) {
return (sec.flags & llvm::ELF::SHF_ALLOC) == 0 &&
sec.name.startswith(".debug");
}
extern SmallVector<InputSectionBase *, 0> inputSections;
extern llvm::DenseSet<std::pair<const Symbol *, uint64_t>> ppc64noTocRelax;
}
std::string toString(const elf::InputSectionBase *);
}
#endif