[LLD] Add CLASS syntax to SECTIONS (#95323)

This allows the input section matching algorithm to be separated from
output section descriptions. This allows a group of sections to be
assigned to multiple output sections, providing an explicit version of
--enable-non-contiguous-regions's spilling that doesn't require altering
global linker script matching behavior with a flag. It also makes the
linker script language more expressive even if spilling is not intended,
since input section matching can be done in a different order than
sections are placed in an output section.

The implementation reuses the backend mechanism provided by
--enable-non-contiguous-regions, so it has roughly similar semantics and
limitations. In particular, sections cannot be spilled into or out of
INSERT, OVERWRITE_SECTIONS, or /DISCARD/. The former two aren't
intrinsic, so it may be possible to relax those restrictions later.
This commit is contained in:
Daniel Thornburgh
2024-08-05 13:06:45 -07:00
committed by GitHub
parent 88d288489e
commit 7e8a9020b1
10 changed files with 777 additions and 102 deletions

View File

@@ -87,6 +87,8 @@ private:
OutputDesc *readOverlaySectionDescription();
OutputDesc *readOutputSectionDescription(StringRef outSec);
SmallVector<SectionCommand *, 0> readOverlay();
SectionClassDesc *readSectionClassDescription();
StringRef readSectionClassName();
SmallVector<StringRef, 0> readOutputSectionPhdrs();
std::pair<uint64_t, uint64_t> readInputSectionFlags();
InputSectionDescription *readInputSectionDescription(StringRef tok);
@@ -605,6 +607,33 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
return v;
}
SectionClassDesc *ScriptParser::readSectionClassDescription() {
StringRef name = readSectionClassName();
SectionClassDesc *desc = make<SectionClassDesc>(name);
if (!script->sectionClasses.insert({CachedHashStringRef(name), desc}).second)
setError("section class '" + name + "' already defined");
expect("{");
while (auto tok = till("}")) {
if (tok == "(" || tok == ")") {
setError("expected filename pattern");
} else if (peek() == "(") {
InputSectionDescription *isd = readInputSectionDescription(tok);
if (!isd->classRef.empty())
setError("section class '" + name + "' references class '" +
isd->classRef + "'");
desc->sc.commands.push_back(isd);
}
}
return desc;
}
StringRef ScriptParser::readSectionClassName() {
expect("(");
StringRef name = unquote(next());
expect(")");
return name;
}
void ScriptParser::readOverwriteSections() {
expect("{");
while (auto tok = till("}"))
@@ -619,7 +648,12 @@ void ScriptParser::readSections() {
for (SectionCommand *cmd : readOverlay())
v.push_back(cmd);
continue;
} else if (tok == "INCLUDE") {
}
if (tok == "CLASS") {
v.push_back(readSectionClassDescription());
continue;
}
if (tok == "INCLUDE") {
readInclude();
continue;
}
@@ -822,8 +856,14 @@ ScriptParser::readInputSectionDescription(StringRef tok) {
expect("(");
if (consume("INPUT_SECTION_FLAGS"))
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
InputSectionDescription *cmd =
readInputSectionRules(next(), withFlags, withoutFlags);
tok = next();
InputSectionDescription *cmd;
if (tok == "CLASS")
cmd = make<InputSectionDescription>(StringRef{}, withFlags, withoutFlags,
readSectionClassName());
else
cmd = readInputSectionRules(tok, withFlags, withoutFlags);
expect(")");
script->keptSections.push_back(cmd);
return cmd;
@@ -832,6 +872,9 @@ ScriptParser::readInputSectionDescription(StringRef tok) {
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
tok = next();
}
if (tok == "CLASS")
return make<InputSectionDescription>(StringRef{}, withFlags, withoutFlags,
readSectionClassName());
return readInputSectionRules(tok, withFlags, withoutFlags);
}
@@ -951,8 +994,12 @@ OutputDesc *ScriptParser::readOverlaySectionDescription() {
std::tie(withFlags, withoutFlags) = readInputSectionFlags();
tok = till("");
}
osd->osec.commands.push_back(
readInputSectionRules(tok, withFlags, withoutFlags));
if (tok == "CLASS")
osd->osec.commands.push_back(make<InputSectionDescription>(
StringRef{}, withFlags, withoutFlags, readSectionClassName()));
else
osd->osec.commands.push_back(
readInputSectionRules(tok, withFlags, withoutFlags));
}
osd->osec.phdrs = readOutputSectionPhdrs();
return osd;