[lld/mac] Fix nondeterminism in output section ordering
authorNico Weber <thakis@chromium.org>
Mon, 28 Jun 2021 19:29:16 +0000 (15:29 -0400)
committerNico Weber <thakis@chromium.org>
Mon, 28 Jun 2021 22:41:33 +0000 (18:41 -0400)
The two different thread_local_regular sections (__thread_data and
more_thread_data) had nondeterminstic ordering for two reasons:

1. https://reviews.llvm.org/D102972 changed concatOutputSections
   from MapVector to DenseMap, so when we iterate it to make
   output segments, we would add the two sections to the __DATA
   output segment in nondeterministic order.

2. The same change also moved the two stable_sort()s for segments
   and sections to sort(). Since sections with assigned priority
   (such as TLV data) have the same priority for all sections,
   this is incorrect -- we must use stable_sort() so that the
   initial (input-order-based) order remains.

As a side effect, we now (deterministically) put the __common
section in front of __bss (while previously we happened to
put it after it). (__common and __bss are both zerofill so
both have order INT_MAX, but common symbols are added to
inputSections before normal sections are collected.)

Makes lld/test/MachO/tlv.s and lld/test/MachO/tlv-dylib.s pass with
LLVM_ENABLE_EXPENSIVE_CHECKS=ON.

Differential Revision: https://reviews.llvm.org/D105054

lld/MachO/OutputSegment.cpp
lld/MachO/Writer.cpp
lld/test/MachO/tlv-dylib.s

index 77aa50c..8a050c4 100644 (file)
@@ -140,10 +140,15 @@ static int sectionOrder(OutputSection *osec) {
 }
 
 void OutputSegment::sortOutputSections() {
-  llvm::sort(sections, compareByOrder<OutputSection *>(sectionOrder));
+  // Must be stable_sort() to keep special sections such as
+  // S_THREAD_LOCAL_REGULAR in input order.
+  llvm::stable_sort(sections, compareByOrder<OutputSection *>(sectionOrder));
 }
 
 void macho::sortOutputSegments() {
+  // sort() instead of stable_sort() is fine because segmentOrder() is
+  // name-based and getOrCreateOutputSegment() makes there's only a single
+  // segment for every name.
   llvm::sort(outputSegments, compareByOrder<OutputSegment *>(segmentOrder));
 }
 
index 9dca341..ffe5668 100644 (file)
@@ -79,7 +79,10 @@ public:
 
   LCUuid *uuidCommand = nullptr;
   OutputSegment *linkEditSegment = nullptr;
-  DenseMap<NamePair, ConcatOutputSection *> concatOutputSections;
+
+  // Output sections are added to output segments in iteration order
+  // of ConcatOutputSection, so must have deterministic iteration order.
+  MapVector<NamePair, ConcatOutputSection *> concatOutputSections;
 };
 
 // LC_DYLD_INFO_ONLY stores the offsets of symbol import/export information.
index dc6bdef..8a179ff 100644 (file)
 # FLAGS-NEXT:    reloff 0
 # FLAGS-NEXT:    nreloc 0
 # FLAGS-NEXT:      type S_THREAD_LOCAL_ZEROFILL
-# FLAGS:       sectname __bss
+# FLAGS:       sectname __common
 # FLAGS-NEXT:   segname __DATA
 # FLAGS-NEXT:      addr
-# FLAGS-NEXT:      size 0x0000000000002000
+# FLAGS-NEXT:      size 0x0000000000004000
 # FLAGS-NEXT:    offset 0
-# FLAGS-NEXT:     align 2^0 (1)
+# FLAGS-NEXT:     align 2^14 (16384)
 # FLAGS-NEXT:    reloff 0
 # FLAGS-NEXT:    nreloc 0
 # FLAGS-NEXT:      type S_ZEROFILL
-# FLAGS:       sectname __common
+# FLAGS:       sectname __bss
 # FLAGS-NEXT:   segname __DATA
 # FLAGS-NEXT:      addr
-# FLAGS-NEXT:      size 0x0000000000004000
+# FLAGS-NEXT:      size 0x0000000000002000
 # FLAGS-NEXT:    offset 0
-# FLAGS-NEXT:     align 2^14 (16384)
+# FLAGS-NEXT:     align 2^0 (1)
 # FLAGS-NEXT:    reloff 0
 # FLAGS-NEXT:    nreloc 0
 # FLAGS-NEXT:      type S_ZEROFILL