[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:
parent
8321579b28
commit
6c814931bc
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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(); });
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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] +
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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++;
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
|
@ -357,7 +357,7 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -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)
|
||||
|
|
|
@ -31,7 +31,7 @@ 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);
|
||||
|
||||
|
@ -39,8 +39,6 @@ public:
|
|||
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);
|
||||
|
||||
|
@ -119,6 +117,16 @@ private:
|
|||
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);
|
||||
|
|
|
@ -91,8 +91,8 @@ private:
|
|||
std::array<uint8_t, 4> readFill();
|
||||
bool readSectionDirective(OutputSection *cmd, StringRef tok1, StringRef tok2);
|
||||
void readSectionAddressType(OutputSection *cmd);
|
||||
OutputSection *readOverlaySectionDescription();
|
||||
OutputSection *readOutputSectionDescription(StringRef outSec);
|
||||
OutputDesc *readOverlaySectionDescription();
|
||||
OutputDesc *readOutputSectionDescription(StringRef outSec);
|
||||
SmallVector<SectionCommand *, 0> readOverlay();
|
||||
SmallVector<StringRef, 0> readOutputSectionPhdrs();
|
||||
std::pair<uint64_t, uint64_t> readInputSectionFlags();
|
||||
|
@ -534,14 +534,14 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
|
|||
while (!errorCount() && !consume("}")) {
|
||||
// VA is the same for all sections. The LMAs are consecutive in memory
|
||||
// starting from the base load address specified.
|
||||
OutputSection *os = readOverlaySectionDescription();
|
||||
os->addrExpr = addrExpr;
|
||||
OutputDesc *osd = readOverlaySectionDescription();
|
||||
osd->osec.addrExpr = addrExpr;
|
||||
if (prev)
|
||||
os->lmaExpr = [=] { return prev->getLMA() + prev->size; };
|
||||
osd->osec.lmaExpr = [=] { return prev->getLMA() + prev->size; };
|
||||
else
|
||||
os->lmaExpr = lmaExpr;
|
||||
v.push_back(os);
|
||||
prev = os;
|
||||
osd->osec.lmaExpr = lmaExpr;
|
||||
v.push_back(osd);
|
||||
prev = &osd->osec;
|
||||
}
|
||||
|
||||
// According to the specification, at the end of the overlay, the location
|
||||
|
@ -551,7 +551,7 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
|
|||
Expr moveDot = [=] {
|
||||
uint64_t max = 0;
|
||||
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;
|
||||
};
|
||||
v.push_back(make<SymbolAssignment>(".", moveDot, getCurrentLocation()));
|
||||
|
@ -599,8 +599,8 @@ void ScriptParser::readSections() {
|
|||
StringRef where = next();
|
||||
SmallVector<StringRef, 0> names;
|
||||
for (SectionCommand *cmd : v)
|
||||
if (auto *os = dyn_cast<OutputSection>(cmd))
|
||||
names.push_back(os->name);
|
||||
if (auto *os = dyn_cast<OutputDesc>(cmd))
|
||||
names.push_back(os->osec.name);
|
||||
if (!names.empty())
|
||||
script->insertCommands.push_back({std::move(names), isAfter, where});
|
||||
}
|
||||
|
@ -869,45 +869,44 @@ static Expr checkAlignment(Expr e, std::string &loc) {
|
|||
};
|
||||
}
|
||||
|
||||
OutputSection *ScriptParser::readOverlaySectionDescription() {
|
||||
OutputSection *cmd =
|
||||
script->createOutputSection(next(), getCurrentLocation());
|
||||
cmd->inOverlay = true;
|
||||
OutputDesc *ScriptParser::readOverlaySectionDescription() {
|
||||
OutputDesc *osd = script->createOutputSection(next(), getCurrentLocation());
|
||||
osd->osec.inOverlay = true;
|
||||
expect("{");
|
||||
while (!errorCount() && !consume("}")) {
|
||||
uint64_t withFlags = 0;
|
||||
uint64_t withoutFlags = 0;
|
||||
if (consume("INPUT_SECTION_FLAGS"))
|
||||
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
|
||||
cmd->commands.push_back(
|
||||
osd->osec.commands.push_back(
|
||||
readInputSectionRules(next(), withFlags, withoutFlags));
|
||||
}
|
||||
return cmd;
|
||||
return osd;
|
||||
}
|
||||
|
||||
OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
||||
OutputSection *cmd =
|
||||
script->createOutputSection(outSec, getCurrentLocation());
|
||||
OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
||||
OutputDesc *cmd = script->createOutputSection(outSec, getCurrentLocation());
|
||||
OutputSection *osec = &cmd->osec;
|
||||
|
||||
size_t symbolsReferenced = script->referencedSymbols.size();
|
||||
|
||||
if (peek() != ":")
|
||||
readSectionAddressType(cmd);
|
||||
readSectionAddressType(osec);
|
||||
expect(":");
|
||||
|
||||
std::string location = getCurrentLocation();
|
||||
if (consume("AT"))
|
||||
cmd->lmaExpr = readParenExpr();
|
||||
osec->lmaExpr = readParenExpr();
|
||||
if (consume("ALIGN"))
|
||||
cmd->alignExpr = checkAlignment(readParenExpr(), location);
|
||||
osec->alignExpr = checkAlignment(readParenExpr(), location);
|
||||
if (consume("SUBALIGN"))
|
||||
cmd->subalignExpr = checkAlignment(readParenExpr(), location);
|
||||
osec->subalignExpr = checkAlignment(readParenExpr(), location);
|
||||
|
||||
// Parse constraints.
|
||||
if (consume("ONLY_IF_RO"))
|
||||
cmd->constraint = ConstraintKind::ReadOnly;
|
||||
osec->constraint = ConstraintKind::ReadOnly;
|
||||
if (consume("ONLY_IF_RW"))
|
||||
cmd->constraint = ConstraintKind::ReadWrite;
|
||||
osec->constraint = ConstraintKind::ReadWrite;
|
||||
expect("{");
|
||||
|
||||
while (!errorCount() && !consume("}")) {
|
||||
|
@ -915,9 +914,9 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
|||
if (tok == ";") {
|
||||
// Empty commands are allowed. Do nothing here.
|
||||
} else if (SymbolAssignment *assign = readAssignment(tok)) {
|
||||
cmd->commands.push_back(assign);
|
||||
osec->commands.push_back(assign);
|
||||
} else if (ByteCommand *data = readByteCommand(tok)) {
|
||||
cmd->commands.push_back(data);
|
||||
osec->commands.push_back(data);
|
||||
} else if (tok == "CONSTRUCTORS") {
|
||||
// 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.
|
||||
|
@ -928,13 +927,13 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
|||
// https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
|
||||
if (peek() != "(")
|
||||
setError("( expected, but got " + peek());
|
||||
cmd->filler = readFill();
|
||||
osec->filler = readFill();
|
||||
} else if (tok == "SORT") {
|
||||
readSort();
|
||||
} else if (tok == "INCLUDE") {
|
||||
readInclude();
|
||||
} else if (peek() == "(") {
|
||||
cmd->commands.push_back(readInputSectionDescription(tok));
|
||||
osec->commands.push_back(readInputSectionDescription(tok));
|
||||
} else {
|
||||
// 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
|
||||
|
@ -944,27 +943,27 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
|||
// case above.
|
||||
auto *isd = make<InputSectionDescription>(tok);
|
||||
isd->sectionPatterns.push_back({{}, StringMatcher("*")});
|
||||
cmd->commands.push_back(isd);
|
||||
osec->commands.push_back(isd);
|
||||
}
|
||||
}
|
||||
|
||||
if (consume(">"))
|
||||
cmd->memoryRegionName = std::string(next());
|
||||
osec->memoryRegionName = std::string(next());
|
||||
|
||||
if (consume("AT")) {
|
||||
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");
|
||||
|
||||
cmd->phdrs = readOutputSectionPhdrs();
|
||||
osec->phdrs = readOutputSectionPhdrs();
|
||||
|
||||
if (peek() == "=" || peek().startswith("=")) {
|
||||
inExpr = true;
|
||||
consume("=");
|
||||
cmd->filler = readFill();
|
||||
osec->filler = readFill();
|
||||
inExpr = false;
|
||||
}
|
||||
|
||||
|
@ -972,7 +971,7 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef outSec) {
|
|||
consume(",");
|
||||
|
||||
if (script->referencedSymbols.size() > symbolsReferenced)
|
||||
cmd->expressionsUseSymbols = true;
|
||||
osec->expressionsUseSymbols = true;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
@ -1318,7 +1317,7 @@ Expr ScriptParser::readPrimary() {
|
|||
}
|
||||
if (tok == "ADDR") {
|
||||
StringRef name = readParenLiteral();
|
||||
OutputSection *osec = script->getOrCreateOutputSection(name);
|
||||
OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
|
||||
osec->usedInExpression = true;
|
||||
return [=]() -> ExprValue {
|
||||
checkIfExists(*osec, location);
|
||||
|
@ -1343,7 +1342,7 @@ Expr ScriptParser::readPrimary() {
|
|||
}
|
||||
if (tok == "ALIGNOF") {
|
||||
StringRef name = readParenLiteral();
|
||||
OutputSection *osec = script->getOrCreateOutputSection(name);
|
||||
OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
|
||||
return [=] {
|
||||
checkIfExists(*osec, location);
|
||||
return osec->alignment;
|
||||
|
@ -1398,7 +1397,7 @@ Expr ScriptParser::readPrimary() {
|
|||
}
|
||||
if (tok == "LOADADDR") {
|
||||
StringRef name = readParenLiteral();
|
||||
OutputSection *osec = script->getOrCreateOutputSection(name);
|
||||
OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
|
||||
osec->usedInExpression = true;
|
||||
return [=] {
|
||||
checkIfExists(*osec, location);
|
||||
|
@ -1442,7 +1441,7 @@ Expr ScriptParser::readPrimary() {
|
|||
}
|
||||
if (tok == "SIZEOF") {
|
||||
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.
|
||||
// We want to allow SIZEOF(.foo) where .foo is a section which happened to
|
||||
// be empty.
|
||||
|
|
|
@ -2319,7 +2319,7 @@ bool SymtabShndxSection::isNeeded() const {
|
|||
// a .symtab_shndx section when the amount of output sections is huge.
|
||||
size_t size = 0;
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (isa<OutputSection>(cmd))
|
||||
if (isa<OutputDesc>(cmd))
|
||||
++size;
|
||||
return size >= SHN_LORESERVE;
|
||||
}
|
||||
|
|
|
@ -273,9 +273,9 @@ void elf::addReservedSymbols() {
|
|||
|
||||
static OutputSection *findSection(StringRef name, unsigned partition = 1) {
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (auto *sec = dyn_cast<OutputSection>(cmd))
|
||||
if (sec->name == name && sec->partition == partition)
|
||||
return sec;
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
if (osd->osec.name == name && osd->osec.partition == partition)
|
||||
return &osd->osec;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -708,9 +708,10 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
|
|||
// don't create a section symbol for that section.
|
||||
template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
|
||||
for (SectionCommand *cmd : script->sectionCommands) {
|
||||
auto *sec = dyn_cast<OutputSection>(cmd);
|
||||
if (!sec)
|
||||
auto *osd = dyn_cast<OutputDesc>(cmd);
|
||||
if (!osd)
|
||||
continue;
|
||||
OutputSection *sec = &osd->osec;
|
||||
auto i = llvm::find_if(sec->commands, [](SectionCommand *cmd) {
|
||||
if (auto *isd = dyn_cast<InputSectionDescription>(cmd))
|
||||
return !isd->sections.empty();
|
||||
|
@ -974,8 +975,8 @@ static unsigned getSectionRank(const OutputSection &osec) {
|
|||
|
||||
static bool compareSections(const SectionCommand *aCmd,
|
||||
const SectionCommand *bCmd) {
|
||||
const OutputSection *a = cast<OutputSection>(aCmd);
|
||||
const OutputSection *b = cast<OutputSection>(bCmd);
|
||||
const OutputSection *a = &cast<OutputDesc>(aCmd)->osec;
|
||||
const OutputSection *b = &cast<OutputDesc>(bCmd)->osec;
|
||||
|
||||
if (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.
|
||||
// Since each branch corresponds to a bit flag, we can just use
|
||||
// countLeadingZeros.
|
||||
static int getRankProximityAux(OutputSection *a, OutputSection *b) {
|
||||
return countLeadingZeros(a->sortRank ^ b->sortRank);
|
||||
static int getRankProximityAux(const OutputSection &a, const OutputSection &b) {
|
||||
return countLeadingZeros(a.sortRank ^ b.sortRank);
|
||||
}
|
||||
|
||||
static int getRankProximity(OutputSection *a, SectionCommand *b) {
|
||||
auto *sec = dyn_cast<OutputSection>(b);
|
||||
return (sec && sec->hasInputSections) ? getRankProximityAux(a, sec) : -1;
|
||||
auto *osd = dyn_cast<OutputDesc>(b);
|
||||
return (osd && osd->osec.hasInputSections)
|
||||
? getRankProximityAux(*a, osd->osec)
|
||||
: -1;
|
||||
}
|
||||
|
||||
// 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
|
||||
findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
|
||||
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.
|
||||
auto i = std::max_element(b, e, [=](SectionCommand *a, SectionCommand *b) {
|
||||
|
@ -1149,9 +1152,9 @@ findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
|
|||
});
|
||||
if (i == e)
|
||||
return e;
|
||||
auto foundSec = dyn_cast<OutputSection>(*i);
|
||||
if (!foundSec)
|
||||
if (!isa<OutputDesc>(*i))
|
||||
return e;
|
||||
auto foundSec = &cast<OutputDesc>(*i)->osec;
|
||||
|
||||
// Consider all existing sections with the same proximity.
|
||||
int proximity = getRankProximity(sec, *i);
|
||||
|
@ -1165,17 +1168,17 @@ findOrphanPos(SmallVectorImpl<SectionCommand *>::iterator b,
|
|||
// resemble the behavior of GNU ld.
|
||||
sortRank = std::max(sortRank, foundSec->sortRank);
|
||||
for (; i != e; ++i) {
|
||||
auto *curSec = dyn_cast<OutputSection>(*i);
|
||||
if (!curSec || !curSec->hasInputSections)
|
||||
auto *curSecDesc = dyn_cast<OutputDesc>(*i);
|
||||
if (!curSecDesc || !curSecDesc->osec.hasInputSections)
|
||||
continue;
|
||||
if (getRankProximity(sec, curSec) != proximity ||
|
||||
sortRank < curSec->sortRank)
|
||||
if (getRankProximity(sec, curSecDesc) != proximity ||
|
||||
sortRank < curSecDesc->osec.sortRank)
|
||||
break;
|
||||
}
|
||||
|
||||
auto isOutputSecWithInputSections = [](SectionCommand *cmd) {
|
||||
auto *os = dyn_cast<OutputSection>(cmd);
|
||||
return os && os->hasInputSections;
|
||||
auto *osd = dyn_cast<OutputDesc>(cmd);
|
||||
return osd && osd->osec.hasInputSections;
|
||||
};
|
||||
auto j =
|
||||
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();
|
||||
maybeShuffle(order);
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (auto *sec = dyn_cast<OutputSection>(cmd))
|
||||
sortSection(*sec, order);
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
sortSection(osd->osec, order);
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::sortSections() {
|
||||
|
@ -1429,13 +1432,11 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
|
|||
sortInputSections();
|
||||
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (auto *osec = dyn_cast<OutputSection>(cmd))
|
||||
osec->sortRank = getSectionRank(*osec);
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
osd->osec.sortRank = getSectionRank(osd->osec);
|
||||
if (!script->hasSectionsCommand) {
|
||||
// We know that all the OutputSections are contiguous in this case.
|
||||
auto isSection = [](SectionCommand *cmd) {
|
||||
return isa<OutputSection>(cmd);
|
||||
};
|
||||
auto isSection = [](SectionCommand *cmd) { return isa<OutputDesc>(cmd); };
|
||||
std::stable_sort(
|
||||
llvm::find_if(script->sectionCommands, isSection),
|
||||
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 e = script->sectionCommands.end();
|
||||
auto nonScriptI = std::find_if(i, e, [](SectionCommand *cmd) {
|
||||
if (auto *sec = dyn_cast<OutputSection>(cmd))
|
||||
return sec->sectionIndex == UINT32_MAX;
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
return osd->osec.sectionIndex == UINT32_MAX;
|
||||
return false;
|
||||
});
|
||||
|
||||
|
@ -1513,13 +1514,13 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
|
|||
|
||||
while (nonScriptI != e) {
|
||||
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
|
||||
// and insert them with one rotate.
|
||||
unsigned rank = orphan->sortRank;
|
||||
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);
|
||||
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.
|
||||
// Warn because this is error-prone.
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (auto *os = dyn_cast<OutputSection>(cmd))
|
||||
if (os->addr % os->alignment != 0)
|
||||
warn("address (0x" + Twine::utohexstr(os->addr) + ") of section " +
|
||||
os->name + " is not a multiple of alignment (" +
|
||||
Twine(os->alignment) + ")");
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
|
||||
OutputSection *osec = &osd->osec;
|
||||
if (osec->addr % osec->alignment != 0)
|
||||
warn("address (0x" + Twine::utohexstr(osec->addr) + ") of section " +
|
||||
osec->name + " is not a multiple of alignment (" +
|
||||
Twine(osec->alignment) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
// If Input Sections have been shrunk (basic block sections) then
|
||||
|
@ -1819,8 +1822,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
|||
if (!config->relocatable) {
|
||||
addStartEndSymbols();
|
||||
for (SectionCommand *cmd : script->sectionCommands)
|
||||
if (auto *sec = dyn_cast<OutputSection>(cmd))
|
||||
addStartStopSymbols(*sec);
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
addStartStopSymbols(osd->osec);
|
||||
}
|
||||
|
||||
// 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
|
||||
// in.shStrTab.
|
||||
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);
|
||||
osec->sectionIndex = outputSections.size();
|
||||
osec->shName = in.shStrTab->addString(osec->name);
|
||||
|
|
Loading…
Reference in New Issue