[ELF] Heuristic for placing orphan section
Differential revision: https://reviews.llvm.org/D25325
llvm-svn: 286225
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 18d1c7d..7f244d9 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -701,6 +701,22 @@
Sec->assignOffsets();
}
+template <class ELFT>
+static bool canSharePtLoad(const OutputSectionBase<ELFT> &S1,
+ const OutputSectionBase<ELFT> &S2) {
+ if (!(S1.getFlags() & SHF_ALLOC) || !(S2.getFlags() & SHF_ALLOC))
+ return false;
+
+ bool S1IsWrite = S1.getFlags() & SHF_WRITE;
+ bool S2IsWrite = S2.getFlags() & SHF_WRITE;
+ if (S1IsWrite != S2IsWrite)
+ return false;
+
+ if (!S1IsWrite)
+ return true; // RO and RX share a PT_LOAD with linker scripts.
+ return (S1.getFlags() & SHF_EXECINSTR) == (S2.getFlags() & SHF_EXECINSTR);
+}
+
template <class ELFT> void Writer<ELFT>::sortSections() {
if (!ScriptConfig->HasSections) {
std::stable_sort(OutputSections.begin(), OutputSections.end(),
@@ -729,25 +745,46 @@
// The way we define an order then is:
// * First put script sections at the start and sort the script and
// non-script sections independently.
- // * Move each non-script section to the first position where it
- // compareSectionsNonScript less than the successor.
+ // * Move each non-script section to its preferred position. We try
+ // to put each section in the last position where it it can share
+ // a PT_LOAD.
std::stable_sort(OutputSections.begin(), OutputSections.end(),
compareSections<ELFT>);
auto I = OutputSections.begin();
auto E = OutputSections.end();
- auto NonScriptI = std::find_if(I, E, [](OutputSectionBase<ELFT> *S) {
- return Script<ELFT>::X->getSectionIndex(S->getName()) == INT_MAX;
- });
+ auto NonScriptI =
+ std::find_if(OutputSections.begin(), E, [](OutputSectionBase<ELFT> *S) {
+ return Script<ELFT>::X->getSectionIndex(S->getName()) == INT_MAX;
+ });
while (NonScriptI != E) {
- auto FirstGreater =
- std::find_if(I, NonScriptI, [&](OutputSectionBase<ELFT> *S) {
- return compareSectionsNonScript<ELFT>(*NonScriptI, S);
+ auto BestPos =
+ std::max_element(I, NonScriptI, [&](OutputSectionBase<ELFT> *&A,
+ OutputSectionBase<ELFT> *&B) {
+ bool ACanSharePtLoad = canSharePtLoad(**NonScriptI, *A);
+ bool BCanSharePtLoad = canSharePtLoad(**NonScriptI, *B);
+ if (ACanSharePtLoad != BCanSharePtLoad)
+ return BCanSharePtLoad;
+
+ bool ACmp = compareSectionsNonScript<ELFT>(*NonScriptI, A);
+ bool BCmp = compareSectionsNonScript<ELFT>(*NonScriptI, B);
+ if (ACmp != BCmp)
+ return BCmp; // FIXME: missing test
+
+ size_t PosA = &A - &OutputSections[0];
+ size_t PosB = &B - &OutputSections[0];
+ return ACmp ? PosA > PosB : PosA < PosB;
});
- std::rotate(FirstGreater, NonScriptI, NonScriptI + 1);
+
+ // max_element only returns NonScriptI if the range is empty. If the range
+ // is not empty we should consider moving the the element forward one
+ // position.
+ if (BestPos != NonScriptI &&
+ !compareSectionsNonScript<ELFT>(*NonScriptI, *BestPos))
+ ++BestPos;
+ std::rotate(BestPos, NonScriptI, NonScriptI + 1);
++NonScriptI;
- ++I;
}
}