Reference reference
In LinkerScript
:
// lld/ELF/LinkerScript.h
class LinkerScript final{
// PHDRS command list.
std::vector<PhdrsCommand> phdrsCommands;
};
updated in two ways;
The driven function to update the program header commands, in void Writer<ELFT>::finalizeSections()
// lld/ELF/Writer.cpp
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
...
if (!config->relocatable && !config->oFormatBinary) {
for (Partition &part : partitions) {
part.phdrs = script->hasPhdrsCommands() ? script->createPhdrs()
: createPhdrs(part);
if (config->emachine == EM_ARM) {
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
addPhdrForSection(part, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R);
}
...
}
...
Update based on scripts:
// lld/ELF/ScriptParser.cpp
void ScriptParser::readPhdrs() {
expect("{");
while (!errorCount() && !consume("}")) {
PhdrsCommand cmd;
cmd.name = next();
cmd.type = readPhdrType();
while (!errorCount() && !consume(";")) {
if (consume("FILEHDR"))
cmd.hasFilehdr = true;
else if (consume("PHDRS"))
cmd.hasPhdrs = true;
else if (consume("AT"))
cmd.lmaExpr = readParenExpr();
else if (consume("FLAGS"))
cmd.flags = readParenExpr()().getValue();
else
setError("unexpected header attribute: " + next());
}
script->phdrsCommands.push_back(cmd);
}
}
Update by linker itself:
Used here:
To adjust sections after sorting
// lld/ELF/LinkerScript.cpp
void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
for (BaseCommand *base : sectionCommands) {
if (auto *sec = dyn_cast<OutputSection>(base)) {
if (!sec->lmaRegionName.empty()) {
if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName))
sec->lmaRegion = m;
else
error("memory region '" + sec->lmaRegionName + "' not declared");
}
sec->memRegion = findMemoryRegion(sec);
}
}
// If output section command doesn't specify any segments,
// and we haven't previously assigned any section to segment,
// then we simply assign section to the very first load segment.
// Below is an example of such linker script:
// PHDRS { seg PT_LOAD; }
// SECTIONS { .aaa : { *(.aaa) } }
std::vector<StringRef> defPhdrs;
auto firstPtLoad = llvm::find_if(phdrsCommands, [](const PhdrsCommand &cmd) {
return cmd.type == PT_LOAD;
});
if (firstPtLoad != phdrsCommands.end())
defPhdrs.push_back(firstPtLoad->name);
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
for (BaseCommand *base : sectionCommands) {
auto *sec = dyn_cast<OutputSection>(base);
if (!sec)
continue;
if (sec->phdrs.empty()) {
// To match the bfd linker script behaviour, only propagate program
// headers to sections that are allocated.
if (sec->flags & SHF_ALLOC)
sec->phdrs = defPhdrs;
} else {
defPhdrs = sec->phdrs;
}
}
}
To allocate headers???
// lld/ELF/LinkerScrpt.cpp
// When the SECTIONS command is used, try to find an address for the file and
// program headers output sections, which can be added to the first PT_LOAD
// segment when program headers are created.
//
// We check if the headers fit below the first allocated section. If there isn't
// enough space for these sections, we'll remove them from the PT_LOAD segment,
// and we'll also remove the PT_PHDR segment.
void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &phdrs) {
uint64_t min = std::numeric_limits<uint64_t>::max();
for (OutputSection *sec : outputSections)
if (sec->flags & SHF_ALLOC)
min = std::min<uint64_t>(min, sec->addr);
auto it = llvm::find_if(
phdrs, [](const PhdrEntry *e) { return e->p_type == PT_LOAD; });
if (it == phdrs.end())
return;
PhdrEntry *firstPTLoad = *it;
bool hasExplicitHeaders =
llvm::any_of(phdrsCommands, [](const PhdrsCommand &cmd) {
return cmd.hasPhdrs || cmd.hasFilehdr;
});
bool paged = !config->omagic && !config->nmagic;
uint64_t headerSize = getHeaderSize();
if ((paged || hasExplicitHeaders) &&
headerSize <= min - computeBase(min, hasExplicitHeaders)) {
min = alignDown(min - headerSize, config->maxPageSize);
Out::elfHeader->addr = min;
Out::programHeaders->addr = min + Out::elfHeader->size;
return;
}
// Error if we were explicitly asked to allocate headers.
if (hasExplicitHeaders)
error("could not allocate headers");
Out::elfHeader->ptLoad = nullptr;
Out::programHeaders->ptLoad = nullptr;
firstPTLoad->firstSec = findFirstSection(firstPTLoad);
llvm::erase_if(phdrs,
[](const PhdrEntry *e) { return e->p_type == PT_PHDR; });
}
To create program header entries:
// lld/ELF/LinkerScript.cpp
// Creates program headers as instructed by PHDRS linker script command.
std::vector<PhdrEntry *> LinkerScript::createPhdrs() {
std::vector<PhdrEntry *> ret;
// Process PHDRS and FILEHDR keywords because they are not
// real output sections and cannot be added in the following loop.
for (const PhdrsCommand &cmd : phdrsCommands) {
PhdrEntry *phdr = make<PhdrEntry>(cmd.type, cmd.flags ? *cmd.flags : PF_R);
if (cmd.hasFilehdr)
phdr->add(Out::elfHeader);
if (cmd.hasPhdrs)
phdr->add(Out::programHeaders);
if (cmd.lmaExpr) {
phdr->p_paddr = cmd.lmaExpr().getValue();
phdr->hasLMA = true;
}
ret.push_back(phdr);
}
// Add output sections to program headers.
for (OutputSection *sec : outputSections) {
// Assign headers specified by linker script
for (size_t id : getPhdrIndices(sec)) {
ret[id]->add(sec);
if (!phdrsCommands[id].flags.hasValue())
ret[id]->p_flags |= sec->getPhdrFlags();
}
}
return ret;
}
To check whether have .interp section
// lld/ELF/LinkerScript.cpp
// Returns true if we should emit an .interp section.
//
// We usually do. But if PHDRS commands are given, and
// no PT_INTERP is there, there's no place to emit an
// .interp, so we don't do that in that case.
bool LinkerScript::needsInterpSection() {
if (phdrsCommands.empty())
return true;
for (PhdrsCommand &cmd : phdrsCommands)
if (cmd.type == PT_INTERP)
return true;
return false;
}
To get the indices of ELF headers containing specific section:
// lld/ELF/LinkerScript.cpp
// Returns indices of ELF headers containing specific section. Each index is a
// zero based number of ELF header listed within PHDRS {} script block.
std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *cmd) {
std::vector<size_t> ret;
for (StringRef s : cmd->phdrs) {
if (Optional<size_t> idx = getPhdrIndex(phdrsCommands, s))
ret.push_back(*idx);
else if (s != "NONE")
error(cmd->location + ": program header '" + s +
"' is not listed in PHDRS");
}
return ret;
}
//
// Returns the index of the segment named Name.
static Optional<size_t> getPhdrIndex(ArrayRef<PhdrsCommand> vec,
StringRef name) {
for (size_t i = 0; i < vec.size(); ++i)
if (vec[i].name == name)
return i;
return None;
}
To check whether the phdr command exists
// lld/ELF/LinkerScript.h
// class LinkerScript
bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?