[lld] [LLD] Add CLASS syntax to SECTIONS (PR #95323)
Peter Smith via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 18 11:42:29 PDT 2024
================
@@ -490,99 +494,131 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec,
SmallVector<InputSectionBase *, 0>
LinkerScript::computeInputSections(const InputSectionDescription *cmd,
ArrayRef<InputSectionBase *> sections,
- const OutputSection &outCmd) {
+ const SectionBase &outCmd) {
SmallVector<InputSectionBase *, 0> ret;
- SmallVector<size_t, 0> indexes;
- DenseSet<size_t> seen;
DenseSet<InputSectionBase *> spills;
- auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
- llvm::sort(MutableArrayRef<size_t>(indexes).slice(begin, end - begin));
- for (size_t i = begin; i != end; ++i)
- ret[i] = sections[indexes[i]];
- sortInputSections(
- MutableArrayRef<InputSectionBase *>(ret).slice(begin, end - begin),
- config->sortSection, SortSectionPolicy::None);
+
+ const auto flagsMatch = [cmd](InputSectionBase *sec) {
+ return (sec->flags & cmd->withFlags) == cmd->withFlags &&
+ (sec->flags & cmd->withoutFlags) == 0;
};
// Collects all sections that satisfy constraints of Cmd.
- size_t sizeAfterPrevSort = 0;
- for (const SectionPattern &pat : cmd->sectionPatterns) {
- size_t sizeBeforeCurrPat = ret.size();
-
- for (size_t i = 0, e = sections.size(); i != e; ++i) {
- // Skip if the section is dead or has been matched by a previous pattern
- // in this input section description.
- InputSectionBase *sec = sections[i];
- if (!sec->isLive() || seen.contains(i))
- continue;
-
- // For --emit-relocs we have to ignore entries like
- // .rela.dyn : { *(.rela.data) }
- // which are common because they are in the default bfd script.
- // We do not ignore SHT_REL[A] linker-synthesized sections here because
- // want to support scripts that do custom layout for them.
- if (isa<InputSection>(sec) &&
- cast<InputSection>(sec)->getRelocatedSection())
- continue;
-
- // Check the name early to improve performance in the common case.
- if (!pat.sectionPat.match(sec->name))
- continue;
-
- if (!cmd->matchesFile(sec->file) || pat.excludesFile(sec->file) ||
- (sec->flags & cmd->withFlags) != cmd->withFlags ||
- (sec->flags & cmd->withoutFlags) != 0)
- continue;
-
- if (sec->parent) {
- // Skip if not allowing multiple matches.
- if (!config->enableNonContiguousRegions)
+ if (cmd->className.empty()) {
+ DenseSet<size_t> seen;
+ size_t sizeAfterPrevSort = 0;
+ SmallVector<size_t, 0> indexes;
+ auto sortByPositionThenCommandLine = [&](size_t begin, size_t end) {
+ llvm::sort(MutableArrayRef<size_t>(indexes).slice(begin, end - begin));
+ for (size_t i = begin; i != end; ++i)
+ ret[i] = sections[indexes[i]];
+ sortInputSections(
+ MutableArrayRef<InputSectionBase *>(ret).slice(begin, end - begin),
+ config->sortSection, SortSectionPolicy::None);
+ };
+
+ for (const SectionPattern &pat : cmd->sectionPatterns) {
+ size_t sizeBeforeCurrPat = ret.size();
+
+ for (size_t i = 0, e = sections.size(); i != e; ++i) {
+ // Skip if the section is dead or has been matched by a previous pattern
+ // in this input section description.
+ InputSectionBase *sec = sections[i];
+ if (!sec->isLive() || seen.contains(i))
continue;
- // Disallow spilling into /DISCARD/; special handling would be needed
- // for this in address assignment, and the semantics are nebulous.
- if (outCmd.name == "/DISCARD/")
+ // For --emit-relocs we have to ignore entries like
+ // .rela.dyn : { *(.rela.data) }
+ // which are common because they are in the default bfd script.
+ // We do not ignore SHT_REL[A] linker-synthesized sections here because
+ // want to support scripts that do custom layout for them.
+ if (isa<InputSection>(sec) &&
+ cast<InputSection>(sec)->getRelocatedSection())
continue;
- // Skip if the section's first match was /DISCARD/; such sections are
- // always discarded.
- if (sec->parent->name == "/DISCARD/")
+ // Check the name early to improve performance in the common case.
+ if (!pat.sectionPat.match(sec->name))
continue;
- // Skip if the section was already matched by a different input section
- // description within this output section.
- if (sec->parent == &outCmd)
+ if (!cmd->matchesFile(sec->file) || pat.excludesFile(sec->file) ||
+ !flagsMatch(sec))
continue;
- spills.insert(sec);
+ if (sec->parent) {
+ // Skip if not allowing multiple matches.
+ if (!config->enableNonContiguousRegions)
+ continue;
+
+ // Disallow spilling out of or into section classes; that's already a
+ // mechanism for spilling.
+ if (isa<SectionClass>(sec->parent) || isa<SectionClass>(outCmd))
+ continue;
+
+ // Disallow spilling into /DISCARD/; special handling would be needed
+ // for this in address assignment, and the semantics are nebulous.
+ if (outCmd.name == "/DISCARD/")
+ continue;
+
+ // Skip if the section was already matched by a different input
+ // section description within this output section or class.
+ if (sec->parent == &outCmd)
+ continue;
+
+ spills.insert(sec);
+ }
+
+ ret.push_back(sec);
+ indexes.push_back(i);
+ seen.insert(i);
}
- ret.push_back(sec);
- indexes.push_back(i);
- seen.insert(i);
+ if (pat.sortOuter == SortSectionPolicy::Default)
+ continue;
+
+ // Matched sections are ordered by radix sort with the keys being (SORT*,
+ // --sort-section, input order), where SORT* (if present) is most
+ // significant.
+ //
+ // Matched sections between the previous SORT* and this SORT* are sorted
+ // by (--sort-alignment, input order).
+ sortByPositionThenCommandLine(sizeAfterPrevSort, sizeBeforeCurrPat);
+ // Matched sections by this SORT* pattern are sorted using all 3 keys.
+ // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
+ // just sort by sortOuter and sortInner.
+ sortInputSections(
+ MutableArrayRef<InputSectionBase *>(ret).slice(sizeBeforeCurrPat),
+ pat.sortOuter, pat.sortInner);
+ sizeAfterPrevSort = ret.size();
}
- if (pat.sortOuter == SortSectionPolicy::Default)
- continue;
+ // Matched sections after the last SORT* are sorted by (--sort-alignment,
+ // input order).
+ sortByPositionThenCommandLine(sizeAfterPrevSort, ret.size());
+ } else {
+ SectionClassDesc *scd = script->sectionClasses.lookup(cmd->className);
+ if (!scd) {
+ error("undefined section class '" + cmd->className + "'");
+ return ret;
+ }
+ if (!scd->sc.assigned) {
+ error("section class '" + cmd->className + "' referenced by '" +
+ outCmd.name + "' before class definition");
+ return ret;
+ }
- // Matched sections are ordered by radix sort with the keys being (SORT*,
- // --sort-section, input order), where SORT* (if present) is most
- // significant.
- //
- // Matched sections between the previous SORT* and this SORT* are sorted by
- // (--sort-alignment, input order).
- sortByPositionThenCommandLine(sizeAfterPrevSort, sizeBeforeCurrPat);
- // Matched sections by this SORT* pattern are sorted using all 3 keys.
- // ret[sizeBeforeCurrPat,ret.size()) are already in the input order, so we
- // just sort by sortOuter and sortInner.
- sortInputSections(
- MutableArrayRef<InputSectionBase *>(ret).slice(sizeBeforeCurrPat),
- pat.sortOuter, pat.sortInner);
- sizeAfterPrevSort = ret.size();
+ for (InputSectionDescription *isd : scd->sc.commands) {
+ for (InputSectionBase *sec : isd->sectionBases) {
+ if (sec->parent == &outCmd || !flagsMatch(sec))
----------------
smithp35 wrote:
In the non class case there is a helpful comment
```
// Skip if the section was already matched by a different input
// section description within this output section or class.
```
Could be worth a similar comment as I found it helpful when trying to remember out what sec->parent == &outCmd meant.
I'm wondering if it is worth some helper lambda's to name some of the tests. For example `alreadyAssignedToCommand` `for (sec->parent == &outCmd)` and `alreadyAssigned` for `(sec->parent && isa<OutputSection>(sec->parent)` some of these could be used in the non class reference part.
That's purely style preference though, and it may end up looking worse so feel free to ignore.
https://github.com/llvm/llvm-project/pull/95323
More information about the llvm-commits
mailing list