Skip to content

Commit

Permalink
[ELF] Don't use multiple inheritance for OutputSection. NFC
Browse files Browse the repository at this point in the history
Add an OutputDesc class inheriting from SectionCommand. An OutputDesc wraps an
OutputSection. This change allows InputSection::getParent to be inlined.

Differential Revision: https://reviews.llvm.org/D120650
  • Loading branch information
MaskRay committed Mar 8, 2022
1 parent 8321579 commit 6c81493
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 157 deletions.
4 changes: 2 additions & 2 deletions lld/ELF/Driver.cpp
Expand Up @@ -2690,8 +2690,8 @@ void LinkerDriver::link(opt::InputArgList &args) {
// point onwards InputSectionDescription::sections should be used instead of
// sectionBases.
for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd))
sec->finalizeInputSections();
if (auto *osd = dyn_cast<OutputDesc>(cmd))
osd->osec.finalizeInputSections();
llvm::erase_if(inputSections, [](InputSectionBase *s) {
return isa<MergeInputSection>(s);
});
Expand Down
4 changes: 2 additions & 2 deletions lld/ELF/ICF.cpp
Expand Up @@ -568,8 +568,8 @@ template <class ELFT> void ICF<ELFT>::run() {
// InputSectionDescription::sections is populated by processSectionCommands().
// ICF may fold some input sections assigned to output sections. Remove them.
for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd))
for (SectionCommand *subCmd : sec->commands)
if (auto *osd = dyn_cast<OutputDesc>(cmd))
for (SectionCommand *subCmd : osd->osec.commands)
if (auto *isd = dyn_cast<InputSectionDescription>(subCmd))
llvm::erase_if(isd->sections,
[](InputSection *isec) { return !isec->isLive(); });
Expand Down
116 changes: 59 additions & 57 deletions lld/ELF/LinkerScript.cpp
Expand Up @@ -130,26 +130,26 @@ uint64_t ExprValue::getSectionOffset() const {
return getValue() - getSecAddr();
}

OutputSection *LinkerScript::createOutputSection(StringRef name,
StringRef location) {
OutputSection *&secRef = nameToOutputSection[CachedHashStringRef(name)];
OutputSection *sec;
if (secRef && secRef->location.empty()) {
OutputDesc *LinkerScript::createOutputSection(StringRef name,
StringRef location) {
OutputDesc *&secRef = nameToOutputSection[CachedHashStringRef(name)];
OutputDesc *sec;
if (secRef && secRef->osec.location.empty()) {
// There was a forward reference.
sec = secRef;
} else {
sec = make<OutputSection>(name, SHT_PROGBITS, 0);
sec = make<OutputDesc>(name, SHT_PROGBITS, 0);
if (!secRef)
secRef = sec;
}
sec->location = std::string(location);
sec->osec.location = std::string(location);
return sec;
}

OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) {
OutputSection *&cmdRef = nameToOutputSection[CachedHashStringRef(name)];
OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
OutputDesc *&cmdRef = nameToOutputSection[CachedHashStringRef(name)];
if (!cmdRef)
cmdRef = make<OutputSection>(name, SHT_PROGBITS, 0);
cmdRef = make<OutputDesc>(name, SHT_PROGBITS, 0);
return cmdRef;
}

Expand Down Expand Up @@ -279,7 +279,7 @@ getSymbolAssignmentValues(ArrayRef<SectionCommand *> sectionCommands) {
assign->sym->value));
continue;
}
for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands)
for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
if (assign->sym)
ret.try_emplace(assign->sym, std::make_pair(assign->sym->section,
Expand All @@ -305,25 +305,25 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) {
// Process INSERT [AFTER|BEFORE] commands. For each command, we move the
// specified output section to the designated place.
void LinkerScript::processInsertCommands() {
SmallVector<OutputSection *, 0> moves;
SmallVector<OutputDesc *, 0> moves;
for (const InsertCommand &cmd : insertCommands) {
for (StringRef name : cmd.names) {
// If base is empty, it may have been discarded by
// adjustOutputSections(). We do not handle such output sections.
auto from = llvm::find_if(sectionCommands, [&](SectionCommand *subCmd) {
return isa<OutputSection>(subCmd) &&
cast<OutputSection>(subCmd)->name == name;
return isa<OutputDesc>(subCmd) &&
cast<OutputDesc>(subCmd)->osec.name == name;
});
if (from == sectionCommands.end())
continue;
moves.push_back(cast<OutputSection>(*from));
moves.push_back(cast<OutputDesc>(*from));
sectionCommands.erase(from);
}

auto insertPos =
llvm::find_if(sectionCommands, [&cmd](SectionCommand *subCmd) {
auto *to = dyn_cast<OutputSection>(subCmd);
return to != nullptr && to->name == cmd.where;
auto *to = dyn_cast<OutputDesc>(subCmd);
return to != nullptr && to->osec.name == cmd.where;
});
if (insertPos == sectionCommands.end()) {
error("unable to insert " + cmd.names[0] +
Expand Down Expand Up @@ -352,10 +352,10 @@ void LinkerScript::declareSymbols() {
// we can't say for sure if it is going to be included or not.
// Skip such sections for now. Improve the checks if we ever
// need symbols from that sections to be declared early.
auto *sec = cast<OutputSection>(cmd);
if (sec->constraint != ConstraintKind::NoConstraint)
const OutputSection &sec = cast<OutputDesc>(cmd)->osec;
if (sec.constraint != ConstraintKind::NoConstraint)
continue;
for (SectionCommand *cmd : sec->commands)
for (SectionCommand *cmd : sec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
declareSymbol(assign);
}
Expand Down Expand Up @@ -645,18 +645,20 @@ void LinkerScript::processSectionCommands() {

// Process OVERWRITE_SECTIONS first so that it can overwrite the main script
// or orphans.
DenseMap<CachedHashStringRef, OutputSection *> map;
DenseMap<CachedHashStringRef, OutputDesc *> map;
size_t i = 0;
for (OutputSection *osec : overwriteSections)
for (OutputDesc *osd : overwriteSections) {
OutputSection *osec = &osd->osec;
if (process(osec) &&
!map.try_emplace(CachedHashStringRef(osec->name), osec).second)
!map.try_emplace(CachedHashStringRef(osec->name), osd).second)
warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name);
}
for (SectionCommand *&base : sectionCommands)
if (auto *osec = dyn_cast<OutputSection>(base)) {
if (OutputSection *overwrite =
map.lookup(CachedHashStringRef(osec->name))) {
log(overwrite->location + " overwrites " + osec->name);
overwrite->sectionIndex = i++;
if (auto *osd = dyn_cast<OutputDesc>(base)) {
OutputSection *osec = &osd->osec;
if (OutputDesc *overwrite = map.lookup(CachedHashStringRef(osec->name))) {
log(overwrite->osec.location + " overwrites " + osec->name);
overwrite->osec.sectionIndex = i++;
base = overwrite;
} else if (process(osec)) {
osec->sectionIndex = i++;
Expand All @@ -666,9 +668,9 @@ void LinkerScript::processSectionCommands() {
// If an OVERWRITE_SECTIONS specified output section is not in
// sectionCommands, append it to the end. The section will be inserted by
// orphan placement.
for (OutputSection *osec : overwriteSections)
if (osec->partition == 1 && osec->sectionIndex == UINT32_MAX)
sectionCommands.push_back(osec);
for (OutputDesc *osd : overwriteSections)
if (osd->osec.partition == 1 && osd->osec.sectionIndex == UINT32_MAX)
sectionCommands.push_back(osd);
}

void LinkerScript::processSymbolAssignments() {
Expand All @@ -690,7 +692,7 @@ void LinkerScript::processSymbolAssignments() {
if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
addSymbol(assign);
else
for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands)
for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
addSymbol(assign);
}
Expand All @@ -701,22 +703,20 @@ void LinkerScript::processSymbolAssignments() {
static OutputSection *findByName(ArrayRef<SectionCommand *> vec,
StringRef name) {
for (SectionCommand *cmd : vec)
if (auto *sec = dyn_cast<OutputSection>(cmd))
if (sec->name == name)
return sec;
if (auto *osd = dyn_cast<OutputDesc>(cmd))
if (osd->osec.name == name)
return &osd->osec;
return nullptr;
}

static OutputSection *createSection(InputSectionBase *isec,
StringRef outsecName) {
OutputSection *sec = script->createOutputSection(outsecName, "<internal>");
sec->recordSection(isec);
return sec;
static OutputDesc *createSection(InputSectionBase *isec, StringRef outsecName) {
OutputDesc *osd = script->createOutputSection(outsecName, "<internal>");
osd->osec.recordSection(isec);
return osd;
}

static OutputSection *
addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
InputSectionBase *isec, StringRef outsecName) {
static OutputDesc *addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
InputSectionBase *isec, StringRef outsecName) {
// Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r
// option is given. A section with SHT_GROUP defines a "section group", and
// its members have SHF_GROUP attribute. Usually these flags have already been
Expand All @@ -743,8 +743,9 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
return nullptr;
}

out->relocationSection = createSection(isec, outsecName);
return out->relocationSection;
OutputDesc *osd = createSection(isec, outsecName);
out->relocationSection = &osd->osec;
return osd;
}

// The ELF spec just says
Expand Down Expand Up @@ -813,15 +814,15 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
return nullptr;
}

OutputSection *sec = createSection(isec, outsecName);
v.push_back(sec);
return sec;
OutputDesc *osd = createSection(isec, outsecName);
v.push_back(&osd->osec);
return osd;
}

// Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections() {
StringMap<TinyPtrVector<OutputSection *>> map;
SmallVector<OutputSection *, 0> v;
SmallVector<OutputDesc *, 0> v;

auto add = [&](InputSectionBase *s) {
if (s->isLive() && !s->parent) {
Expand All @@ -833,8 +834,8 @@ void LinkerScript::addOrphanSections() {
} else if (OutputSection *sec = findByName(sectionCommands, name)) {
sec->recordSection(s);
} else {
if (OutputSection *os = addInputSec(map, s, name))
v.push_back(os);
if (OutputDesc *osd = addInputSec(map, s, name))
v.push_back(osd);
assert(isa<MergeInputSection>(s) ||
s->getOutputSection()->sectionIndex == UINT32_MAX);
}
Expand Down Expand Up @@ -1138,9 +1139,9 @@ void LinkerScript::adjustOutputSections() {

SmallVector<StringRef, 0> defPhdrs;
for (SectionCommand *&cmd : sectionCommands) {
auto *sec = dyn_cast<OutputSection>(cmd);
if (!sec)
if (!isa<OutputDesc>(cmd))
continue;
auto *sec = &cast<OutputDesc>(cmd)->osec;

// Handle align (e.g. ".foo : ALIGN(16) { ... }").
if (sec->alignExpr)
Expand Down Expand Up @@ -1192,7 +1193,8 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in.
MemoryRegion *hint = nullptr;
for (SectionCommand *cmd : sectionCommands) {
if (auto *sec = dyn_cast<OutputSection>(cmd)) {
if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
OutputSection *sec = &osd->osec;
if (!sec->lmaRegionName.empty()) {
if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName))
sec->lmaRegion = m;
Expand All @@ -1219,8 +1221,8 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't
// explicitly specify them.
for (SectionCommand *cmd : sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd))
maybePropagatePhdrs(*sec, defPhdrs);
if (auto *osd = dyn_cast<OutputDesc>(cmd))
maybePropagatePhdrs(osd->osec, defPhdrs);
}

static uint64_t computeBase(uint64_t min, bool allocateHeaders) {
Expand Down Expand Up @@ -1315,7 +1317,7 @@ const Defined *LinkerScript::assignAddresses() {
assign->size = dot - assign->addr;
continue;
}
assignOffsets(cast<OutputSection>(cmd));
assignOffsets(&cast<OutputDesc>(cmd)->osec);
}

ctx = nullptr;
Expand Down
10 changes: 5 additions & 5 deletions lld/ELF/LinkerScript.h
Expand Up @@ -32,6 +32,7 @@ class InputSectionBase;
class OutputSection;
class SectionBase;
class ThunkSection;
struct OutputDesc;

// This represents an r-value in the linker script.
struct ExprValue {
Expand Down Expand Up @@ -267,8 +268,7 @@ class LinkerScript final {
uint64_t tbssAddr = 0;
};

llvm::DenseMap<llvm::CachedHashStringRef, OutputSection *>
nameToOutputSection;
llvm::DenseMap<llvm::CachedHashStringRef, OutputDesc *> nameToOutputSection;

void addSymbol(SymbolAssignment *cmd);
void assignSymbol(SymbolAssignment *cmd, bool inSec);
Expand Down Expand Up @@ -304,8 +304,8 @@ class LinkerScript final {
uint64_t dot;

public:
OutputSection *createOutputSection(StringRef name, StringRef location);
OutputSection *getOrCreateOutputSection(StringRef name);
OutputDesc *createOutputSection(StringRef name, StringRef location);
OutputDesc *getOrCreateOutputSection(StringRef name);

bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; }
Expand Down Expand Up @@ -357,7 +357,7 @@ class LinkerScript final {
SmallVector<InsertCommand, 0> insertCommands;

// OutputSections specified by OVERWRITE_SECTIONS.
SmallVector<OutputSection *, 0> overwriteSections;
SmallVector<OutputDesc *, 0> overwriteSections;

// Sections that will be warned/errored by --orphan-handling.
SmallVector<const InputSectionBase *, 0> orphanSections;
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/MapFile.cpp
Expand Up @@ -168,7 +168,7 @@ static void writeMapFile(raw_fd_ostream &os) {
continue;
}

osec = cast<OutputSection>(cmd);
osec = &cast<OutputDesc>(cmd)->osec;
writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment);
os << osec->name << '\n';

Expand Down
7 changes: 1 addition & 6 deletions lld/ELF/OutputSections.cpp
Expand Up @@ -68,8 +68,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *shdr) {
}

OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags)
: SectionCommand(OutputSectionKind),
SectionBase(Output, name, flags, /*Entsize*/ 0, /*Alignment*/ 1, type,
: SectionBase(Output, name, flags, /*Entsize*/ 0, /*Alignment*/ 1, type,
/*Info*/ 0, /*Link*/ 0) {}

// We allow sections of types listed below to merged into a
Expand Down Expand Up @@ -251,10 +250,6 @@ uint64_t elf::getHeaderSize() {
return Out::elfHeader->size + Out::programHeaders->size;
}

bool OutputSection::classof(const SectionCommand *c) {
return c->kind == OutputSectionKind;
}

void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) {
assert(isLive());
for (SectionCommand *b : commands)
Expand Down
14 changes: 11 additions & 3 deletions lld/ELF/OutputSections.h
Expand Up @@ -31,16 +31,14 @@ struct CompressedData {
// It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
class OutputSection final : public SectionCommand, public SectionBase {
class OutputSection final : public SectionBase {
public:
OutputSection(StringRef name, uint32_t type, uint64_t flags);

static bool classof(const SectionBase *s) {
return s->kind() == SectionBase::Output;
}

static bool classof(const SectionCommand *c);

uint64_t getLMA() const { return ptLoad ? addr + ptLoad->lmaOffset : addr; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *sHdr);

Expand Down Expand Up @@ -119,6 +117,16 @@ class OutputSection final : public SectionCommand, public SectionBase {
std::array<uint8_t, 4> getFiller();
};

struct OutputDesc final : SectionCommand {
OutputSection osec;
OutputDesc(StringRef name, uint32_t type, uint64_t flags)
: SectionCommand(OutputSectionKind), osec(name, type, flags) {}

static bool classof(const SectionCommand *c) {
return c->kind == OutputSectionKind;
}
};

int getPriority(StringRef s);

InputSection *getFirstInputSection(const OutputSection *os);
Expand Down

0 comments on commit 6c81493

Please sign in to comment.