[ELF] Make elfHeader/programHeaders unique_ptr

This removes some SpecificAlloc instantiations, makes lld smaller, and
drops the small memory waste due to the separate BumpPtrAllocator.
This commit is contained in:
Fangrui Song 2024-11-17 00:25:42 -08:00
parent 53dc4e7600
commit 5b1b6a62b8
7 changed files with 45 additions and 31 deletions

View File

@ -1466,12 +1466,14 @@ template <typename ELFT> void elf::writeARMCmseImportLib(Ctx &ctx) {
SymbolTableBaseSection *impSymTab =
make<SymbolTableSection<ELFT>>(ctx, *strtab);
SmallVector<std::pair<OutputSection *, SyntheticSection *>, 0> osIsPairs;
osIsPairs.emplace_back(make<OutputSection>(ctx, strtab->name, 0, 0), strtab);
osIsPairs.emplace_back(make<OutputSection>(ctx, impSymTab->name, 0, 0),
impSymTab);
osIsPairs.emplace_back(make<OutputSection>(ctx, shstrtab->name, 0, 0),
shstrtab);
SmallVector<std::pair<std::unique_ptr<OutputSection>, SyntheticSection *>, 0>
osIsPairs;
osIsPairs.emplace_back(
std::make_unique<OutputSection>(ctx, strtab->name, 0, 0), strtab);
osIsPairs.emplace_back(
std::make_unique<OutputSection>(ctx, impSymTab->name, 0, 0), impSymTab);
osIsPairs.emplace_back(
std::make_unique<OutputSection>(ctx, shstrtab->name, 0, 0), shstrtab);
llvm::sort(ctx.symtab->cmseSymMap, [&](const auto &a, const auto &b) {
return a.second.sym->getVA(ctx) < b.second.sym->getVA(ctx);

View File

@ -565,8 +565,8 @@ struct Ctx : CommonLinkerContext {
Partition *mainPart = nullptr;
PhdrEntry *tlsPhdr = nullptr;
struct OutSections {
OutputSection *elfHeader;
OutputSection *programHeaders;
std::unique_ptr<OutputSection> elfHeader;
std::unique_ptr<OutputSection> programHeaders;
OutputSection *preinitArray;
OutputSection *initArray;
OutputSection *finiArray;

View File

@ -2973,7 +2973,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
// Create elfHeader early. We need a dummy section in
// addReservedSymbols to mark the created symbols as not absolute.
ctx.out.elfHeader = make<OutputSection>(ctx, "", 0, SHF_ALLOC);
ctx.out.elfHeader = std::make_unique<OutputSection>(ctx, "", 0, SHF_ALLOC);
// We need to create some reserved symbols such as _end. Create them.
if (!ctx.arg.relocatable)

View File

@ -133,6 +133,10 @@ uint64_t ExprValue::getSectionOffset() const {
return getValue() - getSecAddr();
}
// std::unique_ptr<OutputSection> may be incomplete type.
LinkerScript::LinkerScript(Ctx &ctx) : ctx(ctx) {}
LinkerScript::~LinkerScript() {}
OutputDesc *LinkerScript::createOutputSection(StringRef name,
StringRef location) {
OutputDesc *&secRef = nameToOutputSection[CachedHashStringRef(name)];
@ -832,7 +836,7 @@ void LinkerScript::processSymbolAssignments() {
// sh_shndx should not be SHN_UNDEF or SHN_ABS. Create a dummy aether section
// that fills the void outside a section. It has an index of one, which is
// indistinguishable from any other regular section index.
aether = make<OutputSection>(ctx, "", 0, SHF_ALLOC);
aether = std::make_unique<OutputSection>(ctx, "", 0, SHF_ALLOC);
aether->sectionIndex = 1;
// `st` captures the local AddressState and makes it accessible deliberately.
@ -840,7 +844,7 @@ void LinkerScript::processSymbolAssignments() {
// current state through to a lambda function created by the script parser.
AddressState st(*this);
state = &st;
st.outSec = aether;
st.outSec = aether.get();
for (SectionCommand *cmd : sectionCommands) {
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
@ -1509,7 +1513,7 @@ LinkerScript::assignAddresses() {
AddressState st(*this);
state = &st;
errorOnMissingSection = true;
st.outSec = aether;
st.outSec = aether.get();
recordedErrors.clear();
SymbolAssignmentMap oldValues = getSymbolAssignmentValues(sectionCommands);
@ -1648,9 +1652,9 @@ SmallVector<PhdrEntry *, 0> LinkerScript::createPhdrs() {
PhdrEntry *phdr = make<PhdrEntry>(ctx, cmd.type, cmd.flags.value_or(PF_R));
if (cmd.hasFilehdr)
phdr->add(ctx.out.elfHeader);
phdr->add(ctx.out.elfHeader.get());
if (cmd.hasPhdrs)
phdr->add(ctx.out.programHeaders);
phdr->add(ctx.out.programHeaders.get());
if (cmd.lmaExpr) {
phdr->p_paddr = cmd.lmaExpr().getValue();

View File

@ -332,12 +332,15 @@ class LinkerScript final {
// LinkerScript.
AddressState *state = nullptr;
OutputSection *aether;
std::unique_ptr<OutputSection> aether;
uint64_t dot = 0;
public:
LinkerScript(Ctx &ctx) : ctx(ctx) {}
// OutputSection may be incomplete. Avoid inline ctor/dtor.
LinkerScript(Ctx &ctx);
~LinkerScript();
OutputDesc *createOutputSection(StringRef name, StringRef location);
OutputDesc *getOrCreateOutputSection(StringRef name);

View File

@ -4679,7 +4679,8 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
ctx.in.shStrTab =
std::make_unique<StringTableSection>(ctx, ".shstrtab", false);
ctx.out.programHeaders = make<OutputSection>(ctx, "", 0, SHF_ALLOC);
ctx.out.programHeaders =
std::make_unique<OutputSection>(ctx, "", 0, SHF_ALLOC);
ctx.out.programHeaders->addralign = ctx.arg.wordsize;
if (ctx.arg.strip != StripPolicy::All) {

View File

@ -213,7 +213,7 @@ void elf::addReservedSymbols(Ctx &ctx) {
s->resolve(ctx, Defined{ctx, ctx.internalFile, StringRef(), STB_GLOBAL,
STV_HIDDEN, STT_NOTYPE, gotOff, /*size=*/0,
ctx.out.elfHeader});
ctx.out.elfHeader.get()});
ctx.sym.globalOffsetTable = cast<Defined>(s);
}
@ -221,24 +221,27 @@ void elf::addReservedSymbols(Ctx &ctx) {
// this symbol unconditionally even when using a linker script, which
// differs from the behavior implemented by GNU linker which only define
// this symbol if ELF headers are in the memory mapped segment.
addOptionalRegular(ctx, "__ehdr_start", ctx.out.elfHeader, 0, STV_HIDDEN);
addOptionalRegular(ctx, "__ehdr_start", ctx.out.elfHeader.get(), 0,
STV_HIDDEN);
// __executable_start is not documented, but the expectation of at
// least the Android libc is that it points to the ELF header.
addOptionalRegular(ctx, "__executable_start", ctx.out.elfHeader, 0,
addOptionalRegular(ctx, "__executable_start", ctx.out.elfHeader.get(), 0,
STV_HIDDEN);
// __dso_handle symbol is passed to cxa_finalize as a marker to identify
// each DSO. The address of the symbol doesn't matter as long as they are
// different in different DSOs, so we chose the start address of the DSO.
addOptionalRegular(ctx, "__dso_handle", ctx.out.elfHeader, 0, STV_HIDDEN);
addOptionalRegular(ctx, "__dso_handle", ctx.out.elfHeader.get(), 0,
STV_HIDDEN);
// If linker script do layout we do not need to create any standard symbols.
if (ctx.script->hasSectionsCommand)
return;
auto add = [&](StringRef s, int64_t pos) {
return addOptionalRegular(ctx, s, ctx.out.elfHeader, pos, STV_DEFAULT);
return addOptionalRegular(ctx, s, ctx.out.elfHeader.get(), pos,
STV_DEFAULT);
};
ctx.sym.bss = add("__bss_start", 0);
@ -815,10 +818,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
// .rela.dyn will be present in the output.
std::string name = ctx.arg.isRela ? "__rela_iplt_start" : "__rel_iplt_start";
ctx.sym.relaIpltStart =
addOptionalRegular(ctx, name, ctx.out.elfHeader, 0, STV_HIDDEN);
addOptionalRegular(ctx, name, ctx.out.elfHeader.get(), 0, STV_HIDDEN);
name.replace(name.size() - 5, 5, "end");
ctx.sym.relaIpltEnd =
addOptionalRegular(ctx, name, ctx.out.elfHeader, 0, STV_HIDDEN);
addOptionalRegular(ctx, name, ctx.out.elfHeader.get(), 0, STV_HIDDEN);
}
// This function generates assignments for predefined symbols (e.g. _end or
@ -1751,7 +1754,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (!ctx.arg.shared) {
OutputSection *sec = findSection(ctx, ".sdata");
addOptionalRegular(ctx, "__global_pointer$",
sec ? sec : ctx.out.elfHeader, 0x800, STV_DEFAULT);
sec ? sec : ctx.out.elfHeader.get(), 0x800,
STV_DEFAULT);
// Set riscvGlobalPointer to be used by the optional global pointer
// relaxation.
if (ctx.arg.relaxGP) {
@ -2128,8 +2132,8 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() {
if (startSym || stopSym)
os->usedInExpression = true;
} else {
addOptionalRegular(ctx, start, ctx.out.elfHeader, 0);
addOptionalRegular(ctx, end, ctx.out.elfHeader, 0);
addOptionalRegular(ctx, start, ctx.out.elfHeader.get(), 0);
addOptionalRegular(ctx, end, ctx.out.elfHeader.get(), 0);
}
};
@ -2206,7 +2210,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
// The first phdr entry is PT_PHDR which describes the program header
// itself.
if (isMain)
addHdr(PT_PHDR, PF_R)->add(ctx.out.programHeaders);
addHdr(PT_PHDR, PF_R)->add(ctx.out.programHeaders.get());
else
addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent());
@ -2219,8 +2223,8 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
// need to be added here.
if (isMain) {
load = addHdr(PT_LOAD, flags);
load->add(ctx.out.elfHeader);
load->add(ctx.out.programHeaders);
load->add(ctx.out.elfHeader.get());
load->add(ctx.out.programHeaders.get());
}
}
@ -2292,7 +2296,7 @@ SmallVector<PhdrEntry *, 0> Writer<ELFT>::createPhdrs(Partition &part) {
load && !sec->lmaExpr && sec->lmaRegion == load->firstSec->lmaRegion;
if (load && sec != relroEnd &&
sec->memRegion == load->firstSec->memRegion &&
(sameLMARegion || load->lastSec == ctx.out.programHeaders) &&
(sameLMARegion || load->lastSec == ctx.out.programHeaders.get()) &&
(ctx.script->hasSectionsCommand || sec->type == SHT_NOBITS ||
load->lastSec->type != SHT_NOBITS)) {
load->p_flags |= newFlags;