[lld] r282118 - Once more unto the strict weak ordering, once more.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 21 15:36:20 PDT 2016
Author: rafael
Date: Wed Sep 21 17:36:19 2016
New Revision: 282118
URL: http://llvm.org/viewvc/llvm-project?rev=282118&view=rev
Log:
Once more unto the strict weak ordering, once more.
This should finally give a stable sorting over all implementations.
Added:
lld/trunk/test/ELF/linkerscript/sections-sort.s
Modified:
lld/trunk/ELF/Writer.cpp
lld/trunk/test/ELF/linkerscript/sections.s
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=282118&r1=282117&r2=282118&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Sep 21 17:36:19 2016
@@ -51,6 +51,7 @@ private:
void forEachRelSec(
std::function<void(InputSectionBase<ELFT> &, const typename ELFT::Shdr &)>
Fn);
+ void sortSections();
void finalizeSections();
void addPredefinedSections();
bool needsGot();
@@ -435,12 +436,10 @@ template <class ELFT> bool elf::isRelroS
S == ".eh_frame";
}
-// Output section ordering is determined by this function.
template <class ELFT>
-static bool compareSections(OutputSectionBase<ELFT> *A,
- OutputSectionBase<ELFT> *B) {
+static bool compareSectionsNonScript(OutputSectionBase<ELFT> *A,
+ OutputSectionBase<ELFT> *B) {
typedef typename ELFT::uint uintX_t;
-
uintX_t AFlags = A->getFlags();
uintX_t BFlags = B->getFlags();
@@ -451,19 +450,10 @@ static bool compareSections(OutputSectio
if (AIsAlloc != BIsAlloc)
return AIsAlloc;
- // If A and B are mentioned in linker script, use that order.
- int AIndex = Script<ELFT>::X->getSectionIndex(A->getName());
- int BIndex = Script<ELFT>::X->getSectionIndex(B->getName());
- bool AInScript = AIndex != INT_MAX;
- bool BInScript = BIndex != INT_MAX;
- if (AInScript && BInScript)
- return AIndex < BIndex;
-
// We don't have any special requirements for the relative order of two non
// allocatable sections.
- // Just put linker script sections first to satisfy strict weak ordering.
if (!AIsAlloc)
- return AInScript;
+ return false;
// We want the read only sections first so that they go in the PT_LOAD
// covering the program headers at the start of the file.
@@ -512,8 +502,25 @@ static bool compareSections(OutputSectio
return getPPC64SectionRank(A->getName()) <
getPPC64SectionRank(B->getName());
- // Just put linker script sections first to satisfy strict weak ordering.
- return AInScript;
+ return false;
+}
+
+// Output section ordering is determined by this function.
+template <class ELFT>
+static bool compareSections(OutputSectionBase<ELFT> *A,
+ OutputSectionBase<ELFT> *B) {
+ // For now, put sections mentioned in a linker script first.
+ int AIndex = Script<ELFT>::X->getSectionIndex(A->getName());
+ int BIndex = Script<ELFT>::X->getSectionIndex(B->getName());
+ bool AInScript = AIndex != INT_MAX;
+ bool BInScript = BIndex != INT_MAX;
+ if (AInScript != BInScript)
+ return AInScript;
+ // If both are in the script, use that order.
+ if (AInScript)
+ return AIndex < BIndex;
+
+ return compareSectionsNonScript(A, B);
}
template <class ELFT> static bool isDiscarded(InputSectionBase<ELFT> *S) {
@@ -710,6 +717,55 @@ template <class ELFT> void Writer<ELFT>:
Sec->assignOffsets();
}
+template <class ELFT> void Writer<ELFT>::sortSections() {
+ if (!ScriptConfig->HasSections) {
+ std::stable_sort(OutputSections.begin(), OutputSections.end(),
+ compareSectionsNonScript<ELFT>);
+ return;
+ }
+
+ // The order of the sections in the script is arbitrary and may not agree with
+ // compareSectionsNonScript. This means that we cannot easily define a
+ // strict weak ordering. To see why, consider a comparison of a section in the
+ // script and one not in the script. We have a two simple options:
+ // * Make them equivalent (a is not less than b, and b is not less than a).
+ // The problem is then that equivalence has to be transitive and we can
+ // have sections a, b and c with only b in a script and a less than c
+ // which breaks this property.
+ // * Use compareSectionsNonScript. Given that the script order doesn't have
+ // to match, we can end up with sections a, b, c, d where b and c are in the
+ // script and c is compareSectionsNonScript less than b. In which case d
+ // can be equivalent to c, a to b and d < a. As a concrete example:
+ // .a (rx) # not in script
+ // .b (rx) # in script
+ // .c (ro) # in script
+ // .d (ro) # not in script
+ //
+ // 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.
+
+ 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;
+ });
+ while (NonScriptI != E) {
+ auto FirstGreater =
+ std::find_if(I, NonScriptI, [&](OutputSectionBase<ELFT> *S) {
+ return compareSectionsNonScript<ELFT>(*NonScriptI, S);
+ });
+ std::rotate(FirstGreater, NonScriptI, NonScriptI + 1);
+ ++NonScriptI;
+ ++I;
+ }
+}
+
// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::finalizeSections() {
Out<ELFT>::PreinitArray = findSection(".preinit_array");
@@ -783,8 +839,7 @@ template <class ELFT> void Writer<ELFT>:
// This function adds linker-created Out<ELFT>::* sections.
addPredefinedSections();
- std::stable_sort(OutputSections.begin(), OutputSections.end(),
- compareSections<ELFT>);
+ sortSections();
unsigned I = 1;
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
Added: lld/trunk/test/ELF/linkerscript/sections-sort.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/sections-sort.s?rev=282118&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/sections-sort.s (added)
+++ lld/trunk/test/ELF/linkerscript/sections-sort.s Wed Sep 21 17:36:19 2016
@@ -0,0 +1,29 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+
+# RUN: echo "SECTIONS { \
+# RUN: .text : { *(.text) } \
+# RUN: foo : { *(foo) } \
+# RUN: } " > %t.script
+# RUN: ld.lld -o %t --script %t.script %t.o -shared
+# RUN: llvm-objdump --section-headers %t | FileCheck %s
+
+# Test the section order. This is a case where at least with libstdc++'s
+# stable_sort we used to get a different result.
+
+nop
+
+.section foo, "a"
+.byte 0
+
+# CHECK: Id
+# CHECK-NEXT: 0
+# CHECK-NEXT: 1 .dynsym
+# CHECK-NEXT: 2 .hash
+# CHECK-NEXT: 3 .dynstr
+# CHECK-NEXT: 4 .text
+# CHECK-NEXT: 5 foo
+# CHECK-NEXT: 6 .dynamic
+# CHECK-NEXT: 7 .symtab
+# CHECK-NEXT: 8 .shstrtab
+# CHECK-NEXT: 9 .strtab
Modified: lld/trunk/test/ELF/linkerscript/sections.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/sections.s?rev=282118&r1=282117&r2=282118&view=diff
==============================================================================
--- lld/trunk/test/ELF/linkerscript/sections.s (original)
+++ lld/trunk/test/ELF/linkerscript/sections.s Wed Sep 21 17:36:19 2016
@@ -42,12 +42,12 @@
# Idx Name Size
# SEC-ORDER: 1 .bss 00000002 {{[0-9a-f]*}} BSS
# SEC-ORDER: 2 other 00000003 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 3 .data 00000020 {{[0-9a-f]*}} DATA
-# SEC-ORDER: 4 .text 0000000e {{[0-9a-f]*}} TEXT DATA
-# SEC-ORDER: 5 .shstrtab 00000002 {{[0-9a-f]*}}
-# SEC-ORDER: 6 .shstrtab 00000032 {{[0-9a-f]*}}
-# SEC-ORDER: 7 .symtab 00000030 {{[0-9a-f]*}}
-# SEC-ORDER: 8 .strtab 00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 3 .shstrtab 00000002 {{[0-9a-f]*}}
+# SEC-ORDER: 4 .shstrtab 00000032 {{[0-9a-f]*}}
+# SEC-ORDER: 5 .symtab 00000030 {{[0-9a-f]*}}
+# SEC-ORDER: 6 .strtab 00000008 {{[0-9a-f]*}}
+# SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA
+# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA
# .text and .data have swapped names but proper sizes and types.
# RUN: echo "SECTIONS { \
More information about the llvm-commits
mailing list