[ELF] - Linkerscript: reimplemented output sections constrains matching functionality.
Previously filtering that was used worked incorrectly.
For example for next script it would just remove both sections completely:
SECTIONS {
. = 0x1000;
.aaa : ONLY_IF_RW { *(.aaa.*) }
. = 0x2000;
.aaa : ONLY_IF_RO { *(.aaa.*) }
}
Patch fixes above issues and adds testcase showing the issue. Testcase is a subset of
FreeBSD script which has:
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
...
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
Differential revision: https://reviews.llvm.org/D23326
llvm-svn: 278486
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 64918d7..1c24614 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -216,20 +216,33 @@
}
template <class ELFT>
+static bool matchConstraints(ArrayRef<InputSectionBase<ELFT> *> Sections,
+ ConstraintKind Kind) {
+ bool RO = (Kind == ConstraintKind::ReadOnly);
+ bool RW = (Kind == ConstraintKind::ReadWrite);
+ return !llvm::any_of(Sections, [=](InputSectionBase<ELFT> *Sec) {
+ bool Writable = Sec->getSectionHdr()->sh_flags & SHF_WRITE;
+ return (RO && Writable) || (RW && !Writable);
+ });
+}
+
+template <class ELFT>
std::vector<InputSectionBase<ELFT> *>
-LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &Cmd) {
+LinkerScript<ELFT>::createInputSectionList(OutputSectionCommand &OutCmd) {
std::vector<InputSectionBase<ELFT> *> Ret;
- for (const std::unique_ptr<BaseCommand> &Base : Cmd.Commands) {
- if (auto *Cmd = dyn_cast<SymbolAssignment>(Base.get())) {
- if (shouldDefine<ELFT>(Cmd))
- addSynthetic<ELFT>(Cmd);
- Ret.push_back(new (LAlloc.Allocate()) LayoutInputSection<ELFT>(Cmd));
+ for (const std::unique_ptr<BaseCommand> &Base : OutCmd.Commands) {
+ if (auto *OutCmd = dyn_cast<SymbolAssignment>(Base.get())) {
+ if (shouldDefine<ELFT>(OutCmd))
+ addSynthetic<ELFT>(OutCmd);
+ Ret.push_back(new (LAlloc.Allocate()) LayoutInputSection<ELFT>(OutCmd));
continue;
}
auto *Cmd = cast<InputSectionDescription>(Base.get());
std::vector<InputSectionBase<ELFT> *> V = getInputSections(Cmd);
+ if (!matchConstraints<ELFT>(V, OutCmd.Constraint))
+ continue;
if (Cmd->SortInner)
std::stable_sort(V.begin(), V.end(), getComparator<ELFT>(Cmd->SortInner));
if (Cmd->SortOuter)
@@ -283,38 +296,6 @@
OutSec->addSection(S);
}
}
-
- // Remove from the output all the sections which did not meet
- // the optional constraints.
- filter();
-}
-
-template <class R, class T>
-static inline void removeElementsIf(R &Range, const T &Pred) {
- Range.erase(std::remove_if(Range.begin(), Range.end(), Pred), Range.end());
-}
-
-// Process ONLY_IF_RO and ONLY_IF_RW.
-template <class ELFT> void LinkerScript<ELFT>::filter() {
- // In this loop, we remove output sections if they don't satisfy
- // requested properties.
- for (const std::unique_ptr<BaseCommand> &Base : Opt.Commands) {
- auto *Cmd = dyn_cast<OutputSectionCommand>(Base.get());
- if (!Cmd || Cmd->Name == "/DISCARD/")
- continue;
-
- if (Cmd->Constraint == ConstraintKind::NoConstraint)
- continue;
-
- bool RO = (Cmd->Constraint == ConstraintKind::ReadOnly);
- bool RW = (Cmd->Constraint == ConstraintKind::ReadWrite);
-
- removeElementsIf(*OutputSections, [&](OutputSectionBase<ELFT> *S) {
- bool Writable = (S->getFlags() & SHF_WRITE);
- return S->getName() == Cmd->Name &&
- ((RO && Writable) || (RW && !Writable));
- });
- }
}
template <class ELFT> void assignOffsets(OutputSectionBase<ELFT> *Sec) {