#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 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
};
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 {
SingleStringMatcher filePat;
mutable std::optional<std::pair<const InputFile *, bool>> matchesFileCache;
public:
InputSectionDescription(StringRef filePattern, uint64_t withFlags = 0,
uint64_t withoutFlags = 0)
: SectionCommand(InputSectionKind), filePat(filePattern),
withFlags(withFlags), withoutFlags(withoutFlags) {}
static bool classof(const SectionCommand *c) {
return c->kind == InputSectionKind;
}
bool matchesFile(const InputFile *file) const;
SmallVector<SectionPattern, 0> sectionPatterns;
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();
OutputSection *outSec = nullptr;
MemoryRegion *memRegion = nullptr;
MemoryRegion *lmaRegion = nullptr;
uint64_t lmaOffset = 0;
uint64_t tbssAddr = 0;
};
llvm::DenseMap<llvm::CachedHashStringRef, OutputDesc *> nameToOutputSection;
void addSymbol(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 OutputSection &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;
OutputSection *aether;
uint64_t dot;
public:
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<PhdrEntry *, 0> createPhdrs();
bool needsInterpSection();
bool shouldKeep(InputSectionBase *s);
std::pair<const OutputSection *, const Defined *> assignAddresses();
bool spillSections();
void erasePotentialSpillSections();
void allocateHeaders(SmallVector<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();
static 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;
struct PotentialSpillList {
PotentialSpillSection *head;
PotentialSpillSection *tail;
};
llvm::DenseMap<InputSectionBase *, PotentialSpillList> potentialSpillLists;
};
struct ScriptWrapper {
LinkerScript s;
LinkerScript *operator->() { return &s; }
};
LLVM_LIBRARY_VISIBILITY extern ScriptWrapper script;
}
#endif