#ifndef LLD_ELF_LINKER_SCRIPT_H
#define LLD_ELF_LINKER_SCRIPT_H
#include "Config.h"
#include "InputSection.h"
#include "Writer.h"
#include "lld/Common/LLVM.h"
#include "lld/Common/Strings.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
namespace lld::elf {
class Defined;
class InputFile;
class InputSection;
class InputSectionBase;
class OutputSection;
class SectionBase;
class ThunkSection;
struct OutputDesc;
struct SectionClass;
struct SectionClassDesc;
struct ExprValue {
ExprValue(SectionBase *sec, bool forceAbsolute, uint64_t val,
const Twine &loc)
: sec(sec), val(val), forceAbsolute(forceAbsolute), loc(loc.str()) {}
ExprValue(uint64_t val) : ExprValue(nullptr, false, val, "") {}
bool isAbsolute() const { return forceAbsolute || sec == nullptr; }
uint64_t getValue() const;
uint64_t getSecAddr() const;
uint64_t getSectionOffset() const;
SectionBase *sec;
uint64_t val;
uint64_t alignment = 1;
uint8_t type = llvm::ELF::STT_NOTYPE;
bool forceAbsolute;
std::string loc;
};
using Expr = std::function<ExprValue()>;
enum SectionsCommandKind {
AssignmentKind,
OutputSectionKind,
InputSectionKind,
ByteKind,
ClassKind,
};
struct SectionCommand {
SectionCommand(int k) : kind(k) {}
int kind;
};
struct SymbolAssignment : SectionCommand {
SymbolAssignment(StringRef name, Expr e, unsigned symOrder, std::string loc)
: SectionCommand(AssignmentKind), name(name), expression(e),
symOrder(symOrder), location(loc) {}
static bool classof(const SectionCommand *c) {
return c->kind == AssignmentKind;
}
StringRef name;
Defined *sym = nullptr;
Expr expression;
bool provide = false;
bool hidden = false;
bool dataSegmentRelroEnd = false;
unsigned symOrder;
std::string location;
std::string commandString;
uint64_t addr;
uint64_t size;
};
enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite };
struct MemoryRegion {
MemoryRegion(StringRef name, Expr origin, Expr length, uint32_t flags,
uint32_t invFlags, uint32_t negFlags, uint32_t negInvFlags)
: name(std::string(name)), origin(origin), length(length), flags(flags),
invFlags(invFlags), negFlags(negFlags), negInvFlags(negInvFlags) {}
std::string name;
Expr origin;
Expr length;
uint32_t flags;
uint32_t invFlags;
uint32_t negFlags;
uint32_t negInvFlags;
uint64_t curPos = 0;
uint64_t getOrigin() const { return origin().getValue(); }
uint64_t getLength() const { return length().getValue(); }
bool compatibleWith(uint32_t secFlags) const {
if ((secFlags & negFlags) || (~secFlags & negInvFlags))
return false;
return (secFlags & flags) || (~secFlags & invFlags);
}
};
class SectionPattern {
StringMatcher excludedFilePat;
mutable std::optional<std::pair<const InputFile *, bool>> excludesFileCache;
public:
SectionPattern(StringMatcher &&pat1, StringMatcher &&pat2)
: excludedFilePat(pat1), sectionPat(pat2),
sortOuter(SortSectionPolicy::Default),
sortInner(SortSectionPolicy::Default) {}
bool excludesFile(const InputFile &file) const;
StringMatcher sectionPat;
SortSectionPolicy sortOuter;
SortSectionPolicy sortInner;
};
class InputSectionDescription : public SectionCommand {
enum class MatchType { Trivial, WholeArchive, ArchivesExcluded } matchType;
SingleStringMatcher filePat;
mutable std::optional<std::pair<const InputFile *, bool>> matchesFileCache;
public:
InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0,
uint64_t withoutFlags = 0, StringRef classRef = {})
: SectionCommand(InputSectionKind), matchType(MatchType::Trivial),
filePat(filePattern), classRef(classRef), withFlags(withFlags),
withoutFlags(withoutFlags) {
assert((filePattern.empty() || classRef.empty()) &&
"file pattern and class reference are mutually exclusive");
if (!filePattern.empty()) {
if (filePattern.back() == ':') {
matchType = MatchType::WholeArchive;
filePat = filePattern.drop_back();
} else if (filePattern.front() == ':') {
matchType = MatchType::ArchivesExcluded;
filePat = filePattern.drop_front();
}
}
}
static bool classof(const SectionCommand *c) {
return c->kind == InputSectionKind;
}
bool matchesFile(const InputFile &file) const;
SmallVector<SectionPattern, 0> sectionPatterns;
StringRef classRef;
SmallVector<InputSectionBase *, 0> sectionBases;
SmallVector<InputSection *, 0> sections;
SmallVector<std::pair<ThunkSection *, uint32_t>, 0> thunkSections;
uint64_t withFlags;
uint64_t withoutFlags;
};
struct ByteCommand : SectionCommand {
ByteCommand(Expr e, unsigned size, std::string commandString)
: SectionCommand(ByteKind), commandString(commandString), expression(e),
size(size) {}
static bool classof(const SectionCommand *c) { return c->kind == ByteKind; }
std::string commandString;
Expr expression;
unsigned offset;
unsigned size;
};
struct InsertCommand {
SmallVector<StringRef, 0> names;
bool isAfter;
StringRef where;
};
struct NoCrossRefCommand {
SmallVector<StringRef, 0> outputSections;
bool toFirst = false;
};
struct PhdrsCommand {
StringRef name;
unsigned type = llvm::ELF::PT_NULL;
bool hasFilehdr = false;
bool hasPhdrs = false;
std::optional<unsigned> flags;
Expr lmaExpr = nullptr;
};
class LinkerScript final {
struct AddressState {
AddressState(const LinkerScript &);
OutputSection *outSec = nullptr;
MemoryRegion *memRegion = nullptr;
MemoryRegion *lmaRegion = nullptr;
uint64_t lmaOffset = 0;
uint64_t tbssAddr = 0;
uint64_t overlaySize;
};
Ctx &ctx;
SmallVector<std::unique_ptr<OutputDesc>, 0> descPool;
llvm::DenseMap<llvm::CachedHashStringRef, OutputDesc *> nameToOutputSection;
StringRef getOutputSectionName(const InputSectionBase *s) const;
void addSymbol(SymbolAssignment *cmd);
void declareSymbol(SymbolAssignment *cmd);
void assignSymbol(SymbolAssignment *cmd, bool inSec);
void setDot(Expr e, const Twine &loc, bool inSec);
void expandOutputSection(uint64_t size);
void expandMemoryRegions(uint64_t size);
SmallVector<InputSectionBase *, 0>
computeInputSections(const InputSectionDescription *,
ArrayRef<InputSectionBase *>, const SectionBase &outCmd);
SmallVector<InputSectionBase *, 0> createInputSectionList(OutputSection &cmd);
void discardSynthetic(OutputSection &);
SmallVector<size_t, 0> getPhdrIndices(OutputSection *sec);
std::pair<MemoryRegion *, MemoryRegion *>
findMemoryRegion(OutputSection *sec, MemoryRegion *hint);
bool assignOffsets(OutputSection *sec);
AddressState *state = nullptr;
std::unique_ptr<OutputSection> aether;
uint64_t dot = 0;
public:
LinkerScript(Ctx &ctx);
~LinkerScript();
OutputDesc *createOutputSection(StringRef name, StringRef location);
OutputDesc *getOrCreateOutputSection(StringRef name);
bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; }
void discard(InputSectionBase &s);
ExprValue getSymbolValue(StringRef name, const Twine &loc);
void addOrphanSections();
void diagnoseOrphanHandling() const;
void diagnoseMissingSGSectionAddress() const;
void adjustOutputSections();
void adjustSectionsAfterSorting();
SmallVector<std::unique_ptr<PhdrEntry>, 0> createPhdrs();
bool needsInterpSection();
bool shouldKeep(InputSectionBase *s);
std::pair<const OutputSection *, const Defined *> assignAddresses();
bool spillSections();
void erasePotentialSpillSections();
void allocateHeaders(SmallVector<std::unique_ptr<PhdrEntry>, 0> &phdrs);
void processSectionCommands();
void processSymbolAssignments();
void declareSymbols();
void processInsertCommands();
void printMemoryUsage(raw_ostream &os);
void recordError(const Twine &msg);
void checkFinalScriptConditions() const;
void addScriptReferencedSymbolsToSymTable();
bool shouldAddProvideSym(StringRef symName);
SmallVector<SectionCommand *, 0> sectionCommands;
SmallVector<PhdrsCommand, 0> phdrsCommands;
bool hasSectionsCommand = false;
bool seenDataAlign = false;
bool seenRelroEnd = false;
bool errorOnMissingSection = false;
SmallVector<SmallString<0>, 0> recordedErrors;
SmallVector<InputSectionDescription *, 0> keptSections;
llvm::MapVector<llvm::StringRef, MemoryRegion *> memoryRegions;
SmallVector<llvm::StringRef, 0> referencedSymbols;
SmallVector<InsertCommand, 0> insertCommands;
SmallVector<OutputDesc *, 0> overwriteSections;
SmallVector<NoCrossRefCommand, 0> noCrossRefs;
SmallVector<const InputSectionBase *, 0> orphanSections;
llvm::MapVector<StringRef, SmallVector<StringRef, 0>> provideMap;
llvm::DenseSet<Symbol *> unusedProvideSyms;
struct PotentialSpillList {
PotentialSpillSection *head;
PotentialSpillSection *tail;
};
llvm::DenseMap<InputSectionBase *, PotentialSpillList> potentialSpillLists;
llvm::DenseMap<llvm::CachedHashStringRef, SectionClassDesc *> sectionClasses;
};
}
#endif