[ELF] Don't use multiple inheritance for OutputSection. NFC

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
This commit is contained in:
Fangrui Song 2022-03-08 11:23:41 -08:00
parent 8321579b28
commit 6c814931bc
10 changed files with 165 additions and 157 deletions

View File

@ -2690,8 +2690,8 @@ void LinkerDriver::link(opt::InputArgList &args) {
// point onwards InputSectionDescription::sections should be used instead of // point onwards InputSectionDescription::sections should be used instead of
// sectionBases. // sectionBases.
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
sec->finalizeInputSections(); osd->osec.finalizeInputSections();
llvm::erase_if(inputSections, [](InputSectionBase *s) { llvm::erase_if(inputSections, [](InputSectionBase *s) {
return isa<MergeInputSection>(s); return isa<MergeInputSection>(s);
}); });

View File

@ -568,8 +568,8 @@ template <class ELFT> void ICF<ELFT>::run() {
// InputSectionDescription::sections is populated by processSectionCommands(). // InputSectionDescription::sections is populated by processSectionCommands().
// ICF may fold some input sections assigned to output sections. Remove them. // ICF may fold some input sections assigned to output sections. Remove them.
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
for (SectionCommand *subCmd : sec->commands) for (SectionCommand *subCmd : osd->osec.commands)
if (auto *isd = dyn_cast<InputSectionDescription>(subCmd)) if (auto *isd = dyn_cast<InputSectionDescription>(subCmd))
llvm::erase_if(isd->sections, llvm::erase_if(isd->sections,
[](InputSection *isec) { return !isec->isLive(); }); [](InputSection *isec) { return !isec->isLive(); });

View File

@ -130,26 +130,26 @@ uint64_t ExprValue::getSectionOffset() const {
return getValue() - getSecAddr(); return getValue() - getSecAddr();
} }
OutputSection *LinkerScript::createOutputSection(StringRef name, OutputDesc *LinkerScript::createOutputSection(StringRef name,
StringRef location) { StringRef location) {
OutputSection *&secRef = nameToOutputSection[CachedHashStringRef(name)]; OutputDesc *&secRef = nameToOutputSection[CachedHashStringRef(name)];
OutputSection *sec; OutputDesc *sec;
if (secRef && secRef->location.empty()) { if (secRef && secRef->osec.location.empty()) {
// There was a forward reference. // There was a forward reference.
sec = secRef; sec = secRef;
} else { } else {
sec = make<OutputSection>(name, SHT_PROGBITS, 0); sec = make<OutputDesc>(name, SHT_PROGBITS, 0);
if (!secRef) if (!secRef)
secRef = sec; secRef = sec;
} }
sec->location = std::string(location); sec->osec.location = std::string(location);
return sec; return sec;
} }
OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) { OutputDesc *LinkerScript::getOrCreateOutputSection(StringRef name) {
OutputSection *&cmdRef = nameToOutputSection[CachedHashStringRef(name)]; OutputDesc *&cmdRef = nameToOutputSection[CachedHashStringRef(name)];
if (!cmdRef) if (!cmdRef)
cmdRef = make<OutputSection>(name, SHT_PROGBITS, 0); cmdRef = make<OutputDesc>(name, SHT_PROGBITS, 0);
return cmdRef; return cmdRef;
} }
@ -279,7 +279,7 @@ getSymbolAssignmentValues(ArrayRef<SectionCommand *> sectionCommands) {
assign->sym->value)); assign->sym->value));
continue; continue;
} }
for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands) for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd)) if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
if (assign->sym) if (assign->sym)
ret.try_emplace(assign->sym, std::make_pair(assign->sym->section, ret.try_emplace(assign->sym, std::make_pair(assign->sym->section,
@ -305,25 +305,25 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) {
// Process INSERT [AFTER|BEFORE] commands. For each command, we move the // Process INSERT [AFTER|BEFORE] commands. For each command, we move the
// specified output section to the designated place. // specified output section to the designated place.
void LinkerScript::processInsertCommands() { void LinkerScript::processInsertCommands() {
SmallVector<OutputSection *, 0> moves; SmallVector<OutputDesc *, 0> moves;
for (const InsertCommand &cmd : insertCommands) { for (const InsertCommand &cmd : insertCommands) {
for (StringRef name : cmd.names) { for (StringRef name : cmd.names) {
// If base is empty, it may have been discarded by // If base is empty, it may have been discarded by
// adjustOutputSections(). We do not handle such output sections. // adjustOutputSections(). We do not handle such output sections.
auto from = llvm::find_if(sectionCommands, [&](SectionCommand *subCmd) { auto from = llvm::find_if(sectionCommands, [&](SectionCommand *subCmd) {
return isa<OutputSection>(subCmd) && return isa<OutputDesc>(subCmd) &&
cast<OutputSection>(subCmd)->name == name; cast<OutputDesc>(subCmd)->osec.name == name;
}); });
if (from == sectionCommands.end()) if (from == sectionCommands.end())
continue; continue;
moves.push_back(cast<OutputSection>(*from)); moves.push_back(cast<OutputDesc>(*from));
sectionCommands.erase(from); sectionCommands.erase(from);
} }
auto insertPos = auto insertPos =
llvm::find_if(sectionCommands, [&cmd](SectionCommand *subCmd) { llvm::find_if(sectionCommands, [&cmd](SectionCommand *subCmd) {
auto *to = dyn_cast<OutputSection>(subCmd); auto *to = dyn_cast<OutputDesc>(subCmd);
return to != nullptr && to->name == cmd.where; return to != nullptr && to->osec.name == cmd.where;
}); });
if (insertPos == sectionCommands.end()) { if (insertPos == sectionCommands.end()) {
error("unable to insert " + cmd.names[0] + error("unable to insert " + cmd.names[0] +
@ -352,10 +352,10 @@ void LinkerScript::declareSymbols() {
// we can't say for sure if it is going to be included or not. // 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 // Skip such sections for now. Improve the checks if we ever
// need symbols from that sections to be declared early. // need symbols from that sections to be declared early.
auto *sec = cast<OutputSection>(cmd); const OutputSection &sec = cast<OutputDesc>(cmd)->osec;
if (sec->constraint != ConstraintKind::NoConstraint) if (sec.constraint != ConstraintKind::NoConstraint)
continue; continue;
for (SectionCommand *cmd : sec->commands) for (SectionCommand *cmd : sec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
declareSymbol(assign); declareSymbol(assign);
} }
@ -645,18 +645,20 @@ void LinkerScript::processSectionCommands() {
// Process OVERWRITE_SECTIONS first so that it can overwrite the main script // Process OVERWRITE_SECTIONS first so that it can overwrite the main script
// or orphans. // or orphans.
DenseMap<CachedHashStringRef, OutputSection *> map; DenseMap<CachedHashStringRef, OutputDesc *> map;
size_t i = 0; size_t i = 0;
for (OutputSection *osec : overwriteSections) for (OutputDesc *osd : overwriteSections) {
OutputSection *osec = &osd->osec;
if (process(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); warn("OVERWRITE_SECTIONS specifies duplicate " + osec->name);
}
for (SectionCommand *&base : sectionCommands) for (SectionCommand *&base : sectionCommands)
if (auto *osec = dyn_cast<OutputSection>(base)) { if (auto *osd = dyn_cast<OutputDesc>(base)) {
if (OutputSection *overwrite = OutputSection *osec = &osd->osec;
map.lookup(CachedHashStringRef(osec->name))) { if (OutputDesc *overwrite = map.lookup(CachedHashStringRef(osec->name))) {
log(overwrite->location + " overwrites " + osec->name); log(overwrite->osec.location + " overwrites " + osec->name);
overwrite->sectionIndex = i++; overwrite->osec.sectionIndex = i++;
base = overwrite; base = overwrite;
} else if (process(osec)) { } else if (process(osec)) {
osec->sectionIndex = i++; osec->sectionIndex = i++;
@ -666,9 +668,9 @@ void LinkerScript::processSectionCommands() {
// If an OVERWRITE_SECTIONS specified output section is not in // If an OVERWRITE_SECTIONS specified output section is not in
// sectionCommands, append it to the end. The section will be inserted by // sectionCommands, append it to the end. The section will be inserted by
// orphan placement. // orphan placement.
for (OutputSection *osec : overwriteSections) for (OutputDesc *osd : overwriteSections)
if (osec->partition == 1 && osec->sectionIndex == UINT32_MAX) if (osd->osec.partition == 1 && osd->osec.sectionIndex == UINT32_MAX)
sectionCommands.push_back(osec); sectionCommands.push_back(osd);
} }
void LinkerScript::processSymbolAssignments() { void LinkerScript::processSymbolAssignments() {
@ -690,7 +692,7 @@ void LinkerScript::processSymbolAssignments() {
if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) if (auto *assign = dyn_cast<SymbolAssignment>(cmd))
addSymbol(assign); addSymbol(assign);
else else
for (SectionCommand *subCmd : cast<OutputSection>(cmd)->commands) for (SectionCommand *subCmd : cast<OutputDesc>(cmd)->osec.commands)
if (auto *assign = dyn_cast<SymbolAssignment>(subCmd)) if (auto *assign = dyn_cast<SymbolAssignment>(subCmd))
addSymbol(assign); addSymbol(assign);
} }
@ -701,22 +703,20 @@ void LinkerScript::processSymbolAssignments() {
static OutputSection *findByName(ArrayRef<SectionCommand *> vec, static OutputSection *findByName(ArrayRef<SectionCommand *> vec,
StringRef name) { StringRef name) {
for (SectionCommand *cmd : vec) for (SectionCommand *cmd : vec)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
if (sec->name == name) if (osd->osec.name == name)
return sec; return &osd->osec;
return nullptr; return nullptr;
} }
static OutputSection *createSection(InputSectionBase *isec, static OutputDesc *createSection(InputSectionBase *isec, StringRef outsecName) {
StringRef outsecName) { OutputDesc *osd = script->createOutputSection(outsecName, "<internal>");
OutputSection *sec = script->createOutputSection(outsecName, "<internal>"); osd->osec.recordSection(isec);
sec->recordSection(isec); return osd;
return sec;
} }
static OutputSection * static OutputDesc *addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map, InputSectionBase *isec, StringRef outsecName) {
InputSectionBase *isec, StringRef outsecName) {
// Sections with SHT_GROUP or SHF_GROUP attributes reach here only when the -r // 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 // 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 // its members have SHF_GROUP attribute. Usually these flags have already been
@ -743,8 +743,9 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
return nullptr; return nullptr;
} }
out->relocationSection = createSection(isec, outsecName); OutputDesc *osd = createSection(isec, outsecName);
return out->relocationSection; out->relocationSection = &osd->osec;
return osd;
} }
// The ELF spec just says // The ELF spec just says
@ -813,15 +814,15 @@ addInputSec(StringMap<TinyPtrVector<OutputSection *>> &map,
return nullptr; return nullptr;
} }
OutputSection *sec = createSection(isec, outsecName); OutputDesc *osd = createSection(isec, outsecName);
v.push_back(sec); v.push_back(&osd->osec);
return sec; return osd;
} }
// Add sections that didn't match any sections command. // Add sections that didn't match any sections command.
void LinkerScript::addOrphanSections() { void LinkerScript::addOrphanSections() {
StringMap<TinyPtrVector<OutputSection *>> map; StringMap<TinyPtrVector<OutputSection *>> map;
SmallVector<OutputSection *, 0> v; SmallVector<OutputDesc *, 0> v;
auto add = [&](InputSectionBase *s) { auto add = [&](InputSectionBase *s) {
if (s->isLive() && !s->parent) { if (s->isLive() && !s->parent) {
@ -833,8 +834,8 @@ void LinkerScript::addOrphanSections() {
} else if (OutputSection *sec = findByName(sectionCommands, name)) { } else if (OutputSection *sec = findByName(sectionCommands, name)) {
sec->recordSection(s); sec->recordSection(s);
} else { } else {
if (OutputSection *os = addInputSec(map, s, name)) if (OutputDesc *osd = addInputSec(map, s, name))
v.push_back(os); v.push_back(osd);
assert(isa<MergeInputSection>(s) || assert(isa<MergeInputSection>(s) ||
s->getOutputSection()->sectionIndex == UINT32_MAX); s->getOutputSection()->sectionIndex == UINT32_MAX);
} }
@ -1138,9 +1139,9 @@ void LinkerScript::adjustOutputSections() {
SmallVector<StringRef, 0> defPhdrs; SmallVector<StringRef, 0> defPhdrs;
for (SectionCommand *&cmd : sectionCommands) { for (SectionCommand *&cmd : sectionCommands) {
auto *sec = dyn_cast<OutputSection>(cmd); if (!isa<OutputDesc>(cmd))
if (!sec)
continue; continue;
auto *sec = &cast<OutputDesc>(cmd)->osec;
// Handle align (e.g. ".foo : ALIGN(16) { ... }"). // Handle align (e.g. ".foo : ALIGN(16) { ... }").
if (sec->alignExpr) if (sec->alignExpr)
@ -1192,7 +1193,8 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Try and find an appropriate memory region to assign offsets in. // Try and find an appropriate memory region to assign offsets in.
MemoryRegion *hint = nullptr; MemoryRegion *hint = nullptr;
for (SectionCommand *cmd : sectionCommands) { 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 (!sec->lmaRegionName.empty()) {
if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName)) if (MemoryRegion *m = memoryRegions.lookup(sec->lmaRegionName))
sec->lmaRegion = m; sec->lmaRegion = m;
@ -1219,8 +1221,8 @@ void LinkerScript::adjustSectionsAfterSorting() {
// Walk the commands and propagate the program headers to commands that don't // Walk the commands and propagate the program headers to commands that don't
// explicitly specify them. // explicitly specify them.
for (SectionCommand *cmd : sectionCommands) for (SectionCommand *cmd : sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
maybePropagatePhdrs(*sec, defPhdrs); maybePropagatePhdrs(osd->osec, defPhdrs);
} }
static uint64_t computeBase(uint64_t min, bool allocateHeaders) { static uint64_t computeBase(uint64_t min, bool allocateHeaders) {
@ -1315,7 +1317,7 @@ const Defined *LinkerScript::assignAddresses() {
assign->size = dot - assign->addr; assign->size = dot - assign->addr;
continue; continue;
} }
assignOffsets(cast<OutputSection>(cmd)); assignOffsets(&cast<OutputDesc>(cmd)->osec);
} }
ctx = nullptr; ctx = nullptr;

View File

@ -32,6 +32,7 @@ class InputSectionBase;
class OutputSection; class OutputSection;
class SectionBase; class SectionBase;
class ThunkSection; class ThunkSection;
struct OutputDesc;
// This represents an r-value in the linker script. // This represents an r-value in the linker script.
struct ExprValue { struct ExprValue {
@ -267,8 +268,7 @@ class LinkerScript final {
uint64_t tbssAddr = 0; uint64_t tbssAddr = 0;
}; };
llvm::DenseMap<llvm::CachedHashStringRef, OutputSection *> llvm::DenseMap<llvm::CachedHashStringRef, OutputDesc *> nameToOutputSection;
nameToOutputSection;
void addSymbol(SymbolAssignment *cmd); void addSymbol(SymbolAssignment *cmd);
void assignSymbol(SymbolAssignment *cmd, bool inSec); void assignSymbol(SymbolAssignment *cmd, bool inSec);
@ -304,8 +304,8 @@ class LinkerScript final {
uint64_t dot; uint64_t dot;
public: public:
OutputSection *createOutputSection(StringRef name, StringRef location); OutputDesc *createOutputSection(StringRef name, StringRef location);
OutputSection *getOrCreateOutputSection(StringRef name); OutputDesc *getOrCreateOutputSection(StringRef name);
bool hasPhdrsCommands() { return !phdrsCommands.empty(); } bool hasPhdrsCommands() { return !phdrsCommands.empty(); }
uint64_t getDot() { return dot; } uint64_t getDot() { return dot; }
@ -357,7 +357,7 @@ public:
SmallVector<InsertCommand, 0> insertCommands; SmallVector<InsertCommand, 0> insertCommands;
// OutputSections specified by OVERWRITE_SECTIONS. // OutputSections specified by OVERWRITE_SECTIONS.
SmallVector<OutputSection *, 0> overwriteSections; SmallVector<OutputDesc *, 0> overwriteSections;
// Sections that will be warned/errored by --orphan-handling. // Sections that will be warned/errored by --orphan-handling.
SmallVector<const InputSectionBase *, 0> orphanSections; SmallVector<const InputSectionBase *, 0> orphanSections;

View File

@ -168,7 +168,7 @@ static void writeMapFile(raw_fd_ostream &os) {
continue; continue;
} }
osec = cast<OutputSection>(cmd); osec = &cast<OutputDesc>(cmd)->osec;
writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment); writeHeader(os, osec->addr, osec->getLMA(), osec->size, osec->alignment);
os << osec->name << '\n'; os << osec->name << '\n';

View File

@ -68,8 +68,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *shdr) {
} }
OutputSection::OutputSection(StringRef name, uint32_t type, uint64_t flags) 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) {} /*Info*/ 0, /*Link*/ 0) {}
// We allow sections of types listed below to merged into a // We allow sections of types listed below to merged into a
@ -251,10 +250,6 @@ uint64_t elf::getHeaderSize() {
return Out::elfHeader->size + Out::programHeaders->size; 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) { void OutputSection::sort(llvm::function_ref<int(InputSectionBase *s)> order) {
assert(isLive()); assert(isLive());
for (SectionCommand *b : commands) for (SectionCommand *b : commands)

View File

@ -31,7 +31,7 @@ struct CompressedData {
// It is composed of multiple InputSections. // It is composed of multiple InputSections.
// The writer creates multiple OutputSections and assign them unique, // The writer creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs. // non-overlapping file offsets and VAs.
class OutputSection final : public SectionCommand, public SectionBase { class OutputSection final : public SectionBase {
public: public:
OutputSection(StringRef name, uint32_t type, uint64_t flags); OutputSection(StringRef name, uint32_t type, uint64_t flags);
@ -39,8 +39,6 @@ public:
return s->kind() == SectionBase::Output; return s->kind() == SectionBase::Output;
} }
static bool classof(const SectionCommand *c);
uint64_t getLMA() const { return ptLoad ? addr + ptLoad->lmaOffset : addr; } uint64_t getLMA() const { return ptLoad ? addr + ptLoad->lmaOffset : addr; }
template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *sHdr); template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *sHdr);
@ -119,6 +117,16 @@ private:
std::array<uint8_t, 4> getFiller(); 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); int getPriority(StringRef s);
InputSection *getFirstInputSection(const OutputSection *os); InputSection *getFirstInputSection(const OutputSection *os);

View File

@ -91,8 +91,8 @@ private:
std::array<uint8_t, 4> readFill(); std::array<uint8_t, 4> readFill();
bool readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2); bool readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2);
void readSectionAddressType(OutputSection *cmd); void readSectionAddressType(OutputSection *cmd);
OutputSection *readOverlaySectionDescription(); OutputDesc *readOverlaySectionDescription();
OutputSection *readOutputSectionDescription(StringRef outSec); OutputDesc *readOutputSectionDescription(StringRef outSec);
SmallVector<SectionCommand *, 0> readOverlay(); SmallVector<SectionCommand *, 0> readOverlay();
SmallVector<StringRef, 0> readOutputSectionPhdrs(); SmallVector<StringRef, 0> readOutputSectionPhdrs();
std::pair<uint64_t, uint64_t> readInputSectionFlags(); std::pair<uint64_t, uint64_t> readInputSectionFlags();
@ -534,14 +534,14 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
while (!errorCount() && !consume("}")) { while (!errorCount() && !consume("}")) {
// VA is the same for all sections. The LMAs are consecutive in memory // VA is the same for all sections. The LMAs are consecutive in memory
// starting from the base load address specified. // starting from the base load address specified.
OutputSection *os = readOverlaySectionDescription(); OutputDesc *osd = readOverlaySectionDescription();
os->addrExpr = addrExpr; osd->osec.addrExpr = addrExpr;
if (prev) if (prev)
os->lmaExpr = [=] { return prev->getLMA() + prev->size; }; osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; };
else else
os->lmaExpr = lmaExpr; osd->osec.lmaExpr = lmaExpr;
v.push_back(os); v.push_back(osd);
prev = os; prev = &osd->osec;
} }
// According to the specification, at the end of the overlay, the location // According to the specification, at the end of the overlay, the location
@ -551,7 +551,7 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
Expr moveDot = [=] { Expr moveDot = [=] {
uint64_t max = 0; uint64_t max = 0;
for (SectionCommand *cmd : v) for (SectionCommand *cmd : v)
max = std::max(max, cast<OutputSection>(cmd)->size); max = std::max(max, cast<OutputDesc>(cmd)->osec.size);
return addrExpr().getValue() + max; return addrExpr().getValue() + max;
}; };
v.push_back(make<SymbolAssignment>(".", moveDot, getCurrentLocation())); v.push_back(make<SymbolAssignment>(".", moveDot, getCurrentLocation()));
@ -599,8 +599,8 @@ void ScriptParser::readSections() {
StringRef where = next(); StringRef where = next();
SmallVector<StringRef, 0> names; SmallVector<StringRef, 0> names;
for (SectionCommand *cmd : v) for (SectionCommand *cmd : v)
if (auto *os = dyn_cast<OutputSection>(cmd)) if (auto *os = dyn_cast<OutputDesc>(cmd))
names.push_back(os->name); names.push_back(os->osec.name);
if (!names.empty()) if (!names.empty())
script->insertCommands.push_back({std::move(names), isAfter, where}); script->insertCommands.push_back({std::move(names), isAfter, where});
} }
@ -869,45 +869,44 @@ static Expr checkAlignment(Expr e, std::string &loc) {
}; };
} }
OutputSection *ScriptParser::readOverlaySectionDescription() { OutputDesc *ScriptParser::readOverlaySectionDescription() {
OutputSection *cmd = OutputDesc *osd = script->createOutputSection(next(), getCurrentLocation());
script->createOutputSection(next(), getCurrentLocation()); osd->osec.inOverlay = true;
cmd->inOverlay = true;
expect("{"); expect("{");
while (!errorCount() && !consume("}")) { while (!errorCount() && !consume("}")) {
uint64_t withFlags = 0; uint64_t withFlags = 0;
uint64_t withoutFlags = 0; uint64_t withoutFlags = 0;
if (consume("INPUT_SECTION_FLAGS")) if (consume("INPUT_SECTION_FLAGS"))
std::tie(withFlags, withoutFlags) = readInputSectionFlags(); std::tie(withFlags, withoutFlags) = readInputSectionFlags();
cmd->commands.push_back( osd->osec.commands.push_back(
readInputSectionRules(next(), withFlags, withoutFlags)); readInputSectionRules(next(), withFlags, withoutFlags));
} }
return cmd; return osd;
} }
OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) { OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
OutputSection *cmd = OutputDesc *cmd = script->createOutputSection(outSec, getCurrentLocation());
script->createOutputSection(outSec, getCurrentLocation()); OutputSection *osec = &cmd->osec;
size_t symbolsReferenced = script->referencedSymbols.size(); size_t symbolsReferenced = script->referencedSymbols.size();
if (peek() != ":") if (peek() != ":")
readSectionAddressType(cmd); readSectionAddressType(osec);
expect(":"); expect(":");
std::string location = getCurrentLocation(); std::string location = getCurrentLocation();
if (consume("AT")) if (consume("AT"))
cmd->lmaExpr = readParenExpr(); osec->lmaExpr = readParenExpr();
if (consume("ALIGN")) if (consume("ALIGN"))
cmd->alignExpr = checkAlignment(readParenExpr(), location); osec->alignExpr = checkAlignment(readParenExpr(), location);
if (consume("SUBALIGN")) if (consume("SUBALIGN"))
cmd->subalignExpr = checkAlignment(readParenExpr(), location); osec->subalignExpr = checkAlignment(readParenExpr(), location);
// Parse constraints. // Parse constraints.
if (consume("ONLY_IF_RO")) if (consume("ONLY_IF_RO"))
cmd->constraint = ConstraintKind::ReadOnly; osec->constraint = ConstraintKind::ReadOnly;
if (consume("ONLY_IF_RW")) if (consume("ONLY_IF_RW"))
cmd->constraint = ConstraintKind::ReadWrite; osec->constraint = ConstraintKind::ReadWrite;
expect("{"); expect("{");
while (!errorCount() && !consume("}")) { while (!errorCount() && !consume("}")) {
@ -915,9 +914,9 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
if (tok == ";") { if (tok == ";") {
// Empty commands are allowed. Do nothing here. // Empty commands are allowed. Do nothing here.
} else if (SymbolAssignment *assign = readAssignment(tok)) { } else if (SymbolAssignment *assign = readAssignment(tok)) {
cmd->commands.push_back(assign); osec->commands.push_back(assign);
} else if (ByteCommand *data = readByteCommand(tok)) { } else if (ByteCommand *data = readByteCommand(tok)) {
cmd->commands.push_back(data); osec->commands.push_back(data);
} else if (tok == "CONSTRUCTORS") { } else if (tok == "CONSTRUCTORS") {
// CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
// by name. This is for very old file formats such as ECOFF/XCOFF. // by name. This is for very old file formats such as ECOFF/XCOFF.
@ -928,13 +927,13 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
if (peek() != "(") if (peek() != "(")
setError("( expected, but got " + peek()); setError("( expected, but got " + peek());
cmd->filler = readFill(); osec->filler = readFill();
} else if (tok == "SORT") { } else if (tok == "SORT") {
readSort(); readSort();
} else if (tok == "INCLUDE") { } else if (tok == "INCLUDE") {
readInclude(); readInclude();
} else if (peek() == "(") { } else if (peek() == "(") {
cmd->commands.push_back(readInputSectionDescription(tok)); osec->commands.push_back(readInputSectionDescription(tok));
} else { } else {
// We have a file name and no input sections description. It is not a // We have a file name and no input sections description. It is not a
// commonly used syntax, but still acceptable. In that case, all sections // commonly used syntax, but still acceptable. In that case, all sections
@ -944,27 +943,27 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
// case above. // case above.
auto *isd = make<InputSectionDescription>(tok); auto *isd = make<InputSectionDescription>(tok);
isd->sectionPatterns.push_back({{}, StringMatcher("*")}); isd->sectionPatterns.push_back({{}, StringMatcher("*")});
cmd->commands.push_back(isd); osec->commands.push_back(isd);
} }
} }
if (consume(">")) if (consume(">"))
cmd->memoryRegionName = std::string(next()); osec->memoryRegionName = std::string(next());
if (consume("AT")) { if (consume("AT")) {
expect(">"); expect(">");
cmd->lmaRegionName = std::string(next()); osec->lmaRegionName = std::string(next());
} }
if (cmd->lmaExpr && !cmd->lmaRegionName.empty()) if (osec->lmaExpr && !osec->lmaRegionName.empty())
error("section can't have both LMA and a load region"); error("section can't have both LMA and a load region");
cmd->phdrs = readOutputSectionPhdrs(); osec->phdrs = readOutputSectionPhdrs();
if (peek() == "=" || peek().startswith("=")) { if (peek() == "=" || peek().startswith("=")) {
inExpr = true; inExpr = true;
consume("="); consume("=");
cmd->filler = readFill(); osec->filler = readFill();
inExpr = false; inExpr = false;
} }
@ -972,7 +971,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
consume(","); consume(",");
if (script->referencedSymbols.size() > symbolsReferenced) if (script->referencedSymbols.size() > symbolsReferenced)
cmd->expressionsUseSymbols = true; osec->expressionsUseSymbols = true;
return cmd; return cmd;
} }
@ -1318,7 +1317,7 @@ Expr ScriptParser::readPrimary() {
} }
if (tok == "ADDR") { if (tok == "ADDR") {
StringRef name = readParenLiteral(); StringRef name = readParenLiteral();
OutputSection *osec = script->getOrCreateOutputSection(name); OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
osec->usedInExpression = true; osec->usedInExpression = true;
return [=]() -> ExprValue { return [=]() -> ExprValue {
checkIfExists(*osec, location); checkIfExists(*osec, location);
@ -1343,7 +1342,7 @@ Expr ScriptParser::readPrimary() {
} }
if (tok == "ALIGNOF") { if (tok == "ALIGNOF") {
StringRef name = readParenLiteral(); StringRef name = readParenLiteral();
OutputSection *osec = script->getOrCreateOutputSection(name); OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
return [=] { return [=] {
checkIfExists(*osec, location); checkIfExists(*osec, location);
return osec->alignment; return osec->alignment;
@ -1398,7 +1397,7 @@ Expr ScriptParser::readPrimary() {
} }
if (tok == "LOADADDR") { if (tok == "LOADADDR") {
StringRef name = readParenLiteral(); StringRef name = readParenLiteral();
OutputSection *osec = script->getOrCreateOutputSection(name); OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
osec->usedInExpression = true; osec->usedInExpression = true;
return [=] { return [=] {
checkIfExists(*osec, location); checkIfExists(*osec, location);
@ -1442,7 +1441,7 @@ Expr ScriptParser::readPrimary() {
} }
if (tok == "SIZEOF") { if (tok == "SIZEOF") {
StringRef name = readParenLiteral(); StringRef name = readParenLiteral();
OutputSection *cmd = script->getOrCreateOutputSection(name); OutputSection *cmd = &script->getOrCreateOutputSection(name)->osec;
// Linker script does not create an output section if its content is empty. // Linker script does not create an output section if its content is empty.
// We want to allow SIZEOF(.foo) where .foo is a section which happened to // We want to allow SIZEOF(.foo) where .foo is a section which happened to
// be empty. // be empty.

View File

@ -2319,7 +2319,7 @@ bool SymtabShndxSection::isNeeded() const {
// a .symtab_shndx section when the amount of output sections is huge. // a .symtab_shndx section when the amount of output sections is huge.
size_t size = 0; size_t size = 0;
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (isa<OutputSection>(cmd)) if (isa<OutputDesc>(cmd))
++size; ++size;
return size >= SHN_LORESERVE; return size >= SHN_LORESERVE;
} }

View File

@ -273,9 +273,9 @@ void elf::addReservedSymbols() {
static OutputSection *findSection(StringRef name, unsigned partition = 1) { static OutputSection *findSection(StringRef name, unsigned partition = 1) {
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
if (sec->name == name && sec->partition == partition) if (osd->osec.name == name && osd->osec.partition == partition)
return sec; return &osd->osec;
return nullptr; return nullptr;
} }
@ -708,9 +708,10 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
// don't create a section symbol for that section. // don't create a section symbol for that section.
template <class ELFT> void Writer<ELFT>::addSectionSymbols() { template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
for (SectionCommand *cmd : script->sectionCommands) { for (SectionCommand *cmd : script->sectionCommands) {
auto *sec = dyn_cast<OutputSection>(cmd); auto *osd = dyn_cast<OutputDesc>(cmd);
if (!sec) if (!osd)
continue; continue;
OutputSection *sec = &osd->osec;
auto i = llvm::find_if(sec->commands, [](SectionCommand *cmd) { auto i = llvm::find_if(sec->commands, [](SectionCommand *cmd) {
if (auto *isd = dyn_cast<InputSectionDescription>(cmd)) if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
return !isd->sections.empty(); return !isd->sections.empty();
@ -974,8 +975,8 @@ static unsigned getSectionRank(const OutputSection &osec) {
static bool compareSections(const SectionCommand *aCmd, static bool compareSections(const SectionCommand *aCmd,
const SectionCommand *bCmd) { const SectionCommand *bCmd) {
const OutputSection *a = cast<OutputSection>(aCmd); const OutputSection *a = &cast<OutputDesc>(aCmd)->osec;
const OutputSection *b = cast<OutputSection>(bCmd); const OutputSection *b = &cast<OutputDesc>(bCmd)->osec;
if (a->sortRank != b->sortRank) if (a->sortRank != b->sortRank)
return a->sortRank < b->sortRank; return a->sortRank < b->sortRank;
@ -1106,13 +1107,15 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
// The more branches in getSectionRank that match, the more similar they are. // The more branches in getSectionRank that match, the more similar they are.
// Since each branch corresponds to a bit flag, we can just use // Since each branch corresponds to a bit flag, we can just use
// countLeadingZeros. // countLeadingZeros.
static int getRankProximityAux(OutputSection *a, OutputSection *b) { static int getRankProximityAux(const OutputSection &a, const OutputSection &b) {
return countLeadingZeros(a->sortRank ^ b->sortRank); return countLeadingZeros(a.sortRank ^ b.sortRank);
} }
static int getRankProximity(OutputSection *a, SectionCommand *b) { static int getRankProximity(OutputSection *a, SectionCommand *b) {
auto *sec = dyn_cast<OutputSection>(b); auto *osd = dyn_cast<OutputDesc>(b);
return (sec && sec->hasInputSections) ? getRankProximityAux(a, sec) : -1; return (osd && osd->osec.hasInputSections)
? getRankProximityAux(*a, osd->osec)
: -1;
} }
// When placing orphan sections, we want to place them after symbol assignments // When placing orphan sections, we want to place them after symbol assignments
@ -1141,7 +1144,7 @@ static bool shouldSkip(SectionCommand *cmd) {
static SmallVectorImpl<SectionCommand *>::iterator static SmallVectorImpl<SectionCommand *>::iterator
findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b, findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
SmallVectorImpl<SectionCommand *>::iterator e) { SmallVectorImpl<SectionCommand *>::iterator e) {
OutputSection *sec = cast<OutputSection>(*e); OutputSection *sec = &cast<OutputDesc>(*e)->osec;
// Find the first element that has as close a rank as possible. // Find the first element that has as close a rank as possible.
auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) { auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) {
@ -1149,9 +1152,9 @@ findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
}); });
if (i == e) if (i == e)
return e; return e;
auto foundSec = dyn_cast<OutputSection>(*i); if (!isa<OutputDesc>(*i))
if (!foundSec)
return e; return e;
auto foundSec = &cast<OutputDesc>(*i)->osec;
// Consider all existing sections with the same proximity. // Consider all existing sections with the same proximity.
int proximity = getRankProximity(sec, *i); int proximity = getRankProximity(sec, *i);
@ -1165,17 +1168,17 @@ findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
// resemble the behavior of GNU ld. // resemble the behavior of GNU ld.
sortRank = std::max(sortRank, foundSec->sortRank); sortRank = std::max(sortRank, foundSec->sortRank);
for (; i != e; ++i) { for (; i != e; ++i) {
auto *curSec = dyn_cast<OutputSection>(*i); auto *curSecDesc = dyn_cast<OutputDesc>(*i);
if (!curSec || !curSec->hasInputSections) if (!curSecDesc || !curSecDesc->osec.hasInputSections)
continue; continue;
if (getRankProximity(sec, curSec) != proximity || if (getRankProximity(sec, curSecDesc) != proximity ||
sortRank < curSec->sortRank) sortRank < curSecDesc->osec.sortRank)
break; break;
} }
auto isOutputSecWithInputSections = [](SectionCommand *cmd) { auto isOutputSecWithInputSections = [](SectionCommand *cmd) {
auto *os = dyn_cast<OutputSection>(cmd); auto *osd = dyn_cast<OutputDesc>(cmd);
return os && os->hasInputSections; return osd && osd->osec.hasInputSections;
}; };
auto j = auto j =
std::find_if(std::make_reverse_iterator(i), std::make_reverse_iterator(b), std::find_if(std::make_reverse_iterator(i), std::make_reverse_iterator(b),
@ -1412,8 +1415,8 @@ template <class ELFT> void Writer<ELFT>::sortInputSections() {
DenseMap<const InputSectionBase *, int> order = buildSectionOrder(); DenseMap<const InputSectionBase *, int> order = buildSectionOrder();
maybeShuffle(order); maybeShuffle(order);
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
sortSection(*sec, order); sortSection(osd->osec, order);
} }
template <class ELFT> void Writer<ELFT>::sortSections() { template <class ELFT> void Writer<ELFT>::sortSections() {
@ -1429,13 +1432,11 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
sortInputSections(); sortInputSections();
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *osec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
osec->sortRank = getSectionRank(*osec); osd->osec.sortRank = getSectionRank(osd->osec);
if (!script->hasSectionsCommand) { if (!script->hasSectionsCommand) {
// We know that all the OutputSections are contiguous in this case. // We know that all the OutputSections are contiguous in this case.
auto isSection = [](SectionCommand *cmd) { auto isSection = [](SectionCommand *cmd) { return isa<OutputDesc>(cmd); };
return isa<OutputSection>(cmd);
};
std::stable_sort( std::stable_sort(
llvm::find_if(script->sectionCommands, isSection), llvm::find_if(script->sectionCommands, isSection),
llvm::find_if(llvm::reverse(script->sectionCommands), isSection).base(), llvm::find_if(llvm::reverse(script->sectionCommands), isSection).base(),
@ -1492,8 +1493,8 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
auto i = script->sectionCommands.begin(); auto i = script->sectionCommands.begin();
auto e = script->sectionCommands.end(); auto e = script->sectionCommands.end();
auto nonScriptI = std::find_if(i, e, [](SectionCommand *cmd) { auto nonScriptI = std::find_if(i, e, [](SectionCommand *cmd) {
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
return sec->sectionIndex == UINT32_MAX; return osd->osec.sectionIndex == UINT32_MAX;
return false; return false;
}); });
@ -1513,13 +1514,13 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
while (nonScriptI != e) { while (nonScriptI != e) {
auto pos = findOrphanPos(i, nonScriptI); auto pos = findOrphanPos(i, nonScriptI);
OutputSection *orphan = cast<OutputSection>(*nonScriptI); OutputSection *orphan = &cast<OutputDesc>(*nonScriptI)->osec;
// As an optimization, find all sections with the same sort rank // As an optimization, find all sections with the same sort rank
// and insert them with one rotate. // and insert them with one rotate.
unsigned rank = orphan->sortRank; unsigned rank = orphan->sortRank;
auto end = std::find_if(nonScriptI + 1, e, [=](SectionCommand *cmd) { auto end = std::find_if(nonScriptI + 1, e, [=](SectionCommand *cmd) {
return cast<OutputSection>(cmd)->sortRank != rank; return cast<OutputDesc>(cmd)->osec.sortRank != rank;
}); });
std::rotate(pos, nonScriptI, end); std::rotate(pos, nonScriptI, end);
nonScriptI = end; nonScriptI = end;
@ -1668,11 +1669,13 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
// If addrExpr is set, the address may not be a multiple of the alignment. // If addrExpr is set, the address may not be a multiple of the alignment.
// Warn because this is error-prone. // Warn because this is error-prone.
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *os = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
if (os->addr % os->alignment != 0) OutputSection *osec = &osd->osec;
warn("address (0x" + Twine::utohexstr(os->addr) + ") of section " + if (osec->addr % osec->alignment != 0)
os->name + " is not a multiple of alignment (" + warn("address (0x" + Twine::utohexstr(osec->addr) + ") of section " +
Twine(os->alignment) + ")"); osec->name + " is not a multiple of alignment (" +
Twine(osec->alignment) + ")");
}
} }
// If Input Sections have been shrunk (basic block sections) then // If Input Sections have been shrunk (basic block sections) then
@ -1819,8 +1822,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (!config->relocatable) { if (!config->relocatable) {
addStartEndSymbols(); addStartEndSymbols();
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *sec = dyn_cast<OutputSection>(cmd)) if (auto *osd = dyn_cast<OutputDesc>(cmd))
addStartStopSymbols(*sec); addStartStopSymbols(osd->osec);
} }
// Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type.
@ -1988,7 +1991,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// Create a list of OutputSections, assign sectionIndex, and populate // Create a list of OutputSections, assign sectionIndex, and populate
// in.shStrTab. // in.shStrTab.
for (SectionCommand *cmd : script->sectionCommands) for (SectionCommand *cmd : script->sectionCommands)
if (auto *osec = dyn_cast<OutputSection>(cmd)) { if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
OutputSection *osec = &osd->osec;
outputSections.push_back(osec); outputSections.push_back(osec);
osec->sectionIndex = outputSections.size(); osec->sectionIndex = outputSections.size();
osec->shName = in.shStrTab->addString(osec->name); osec->shName = in.shStrTab->addString(osec->name);