diff --git a/lld/MachO/OutputSection.h b/lld/MachO/OutputSection.h --- a/lld/MachO/OutputSection.h +++ b/lld/MachO/OutputSection.h @@ -12,6 +12,8 @@ #include "lld/Common/LLVM.h" #include "llvm/ADT/DenseMap.h" +#include + namespace lld { namespace macho { @@ -56,6 +58,10 @@ StringRef name; OutputSegment *parent = nullptr; + // For output sections that don't have explicit ordering requirements, their + // output order should be based on the order of the input sections they + // contain. + int inputOrder = std::numeric_limits::max(); uint32_t index = 0; uint64_t addr = 0; diff --git a/lld/MachO/OutputSegment.h b/lld/MachO/OutputSegment.h --- a/lld/MachO/OutputSegment.h +++ b/lld/MachO/OutputSegment.h @@ -12,6 +12,8 @@ #include "OutputSection.h" #include "lld/Common/LLVM.h" +#include + namespace lld { namespace macho { @@ -42,7 +44,7 @@ void addOutputSection(OutputSection *os); void sortOutputSections( llvm::function_ref comparator) { - llvm::stable_sort(sections, comparator); + llvm::sort(sections, comparator); } const std::vector &getSections() const { return sections; } @@ -51,6 +53,7 @@ uint64_t fileOff = 0; uint64_t fileSize = 0; uint64_t vmSize = 0; + int inputOrder = std::numeric_limits::max(); StringRef name; uint32_t maxProt = 0; uint32_t initProt = 0; diff --git a/lld/MachO/OutputSegment.cpp b/lld/MachO/OutputSegment.cpp --- a/lld/MachO/OutputSegment.cpp +++ b/lld/MachO/OutputSegment.cpp @@ -50,6 +50,8 @@ } void OutputSegment::addOutputSection(OutputSection *osec) { + inputOrder = std::min(inputOrder, osec->inputOrder); + osec->parent = this; sections.push_back(osec); diff --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp --- a/lld/MachO/Writer.cpp +++ b/lld/MachO/Writer.cpp @@ -765,7 +765,7 @@ // Make sure __LINKEDIT is the last segment (i.e. all its hidden // sections must be ordered after other sections). .Case(segment_names::linkEdit, std::numeric_limits::max()) - .Default(0); + .Default(seg->inputOrder); } static int sectionOrder(OutputSection *osec) { @@ -779,7 +779,7 @@ .Case(section_names::stubHelper, -1) .Case(section_names::unwindInfo, std::numeric_limits::max() - 1) .Case(section_names::ehFrame, std::numeric_limits::max()) - .Default(0); + .Default(osec->inputOrder); } else if (segname == segment_names::data || segname == segment_names::dataConst) { // For each thread spawned, dyld will initialize its TLVs by copying the @@ -798,9 +798,10 @@ return std::numeric_limits::max(); default: return StringSwitch(osec->name) + .Case(section_names::got, -3) .Case(section_names::lazySymbolPtr, -2) - .Case(section_names::data, -1) - .Default(0); + .Case(section_names::const_, -1) + .Default(osec->inputOrder); } } else if (segname == segment_names::linkEdit) { return StringSwitch(osec->name) @@ -814,13 +815,13 @@ .Case(section_names::indirectSymbolTable, -2) .Case(section_names::stringTable, -1) .Case(section_names::codeSignature, std::numeric_limits::max()) - .Default(0); + .Default(osec->inputOrder); } // ZeroFill sections must always be the at the end of their segments, // otherwise subsequent sections may get overwritten with zeroes at runtime. if (sectionType(osec->flags) == S_ZEROFILL) return std::numeric_limits::max(); - return 0; + return osec->inputOrder; } template @@ -834,8 +835,7 @@ static void sortSegmentsAndSections() { TimeTraceScope timeScope("Sort segments and sections"); - llvm::stable_sort(outputSegments, - compareByOrder(segmentOrder)); + llvm::sort(outputSegments, compareByOrder(segmentOrder)); DenseMap isecPriorities = buildInputSectionPriorities(); @@ -898,14 +898,17 @@ } // Then add input sections to output sections. - MapVector concatOutputSections; - for (InputSection *isec : inputSections) { + DenseMap concatOutputSections; + for (const auto &p : enumerate(inputSections)) { + InputSection *isec = p.value(); if (isec->shouldOmitFromOutput()) continue; NamePair names = maybeRenameSection({isec->segname, isec->name}); ConcatOutputSection *&osec = concatOutputSections[names]; - if (osec == nullptr) + if (osec == nullptr) { osec = make(names.second); + osec->inputOrder = p.index(); + } osec->addInput(isec); } diff --git a/lld/test/MachO/load-command-sequence.s b/lld/test/MachO/load-command-sequence.s --- a/lld/test/MachO/load-command-sequence.s +++ b/lld/test/MachO/load-command-sequence.s @@ -28,10 +28,10 @@ # COMMON: segname __TEXT # COMMON: cmd LC_SEGMENT_64 # COMMON: segname __DATA_CONST -# COMMON: sectname __const -# COMMON: segname __DATA_CONST # COMMON: sectname __got # COMMON: segname __DATA_CONST +# COMMON: sectname __const +# COMMON: segname __DATA_CONST # COMMON: cmd LC_SEGMENT_64 # COMMON: segname __DATA # COMMON: sectname __data diff --git a/lld/test/MachO/section-order.s b/lld/test/MachO/section-order.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/section-order.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 +## Check that section ordering follows from input file ordering. +# RUN: rm -rf %t; split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/1.s -o %t/1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/2.s -o %t/2.o +# RUN: %lld -dylib %t/1.o %t/2.o -o %t/12 +# RUN: %lld -dylib %t/2.o %t/1.o -o %t/21 +# RUN: llvm-objdump --macho --section-headers %t/12 | FileCheck %s --check-prefix=CHECK-12 +# RUN: llvm-objdump --macho --section-headers %t/21 | FileCheck %s --check-prefix=CHECK-21 + +# CHECK-12: __text +# CHECK-12-NEXT: foo +# CHECK-12-NEXT: bar +# CHECK-12-NEXT: __cstring + +# CHECK-21: __text +# CHECK-21-NEXT: __cstring +# CHECK-21-NEXT: bar +# CHECK-21-NEXT: foo + +#--- 1.s +.section __TEXT,foo + .space 1 +.section __TEXT,bar + .space 1 +.cstring + .asciz "" + +#--- 2.s +.cstring + .asciz "" +.section __TEXT,bar + .space 1 +.section __TEXT,foo + .space 1 diff --git a/lld/test/MachO/weak-binding.s b/lld/test/MachO/weak-binding.s --- a/lld/test/MachO/weak-binding.s +++ b/lld/test/MachO/weak-binding.s @@ -4,8 +4,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/libfoo.s -o %t/libfoo.o # RUN: %lld -dylib %t/libfoo.o -o %t/libfoo.dylib # RUN: %lld %t/test.o -L%t -lfoo -o %t/test -lSystem -# RUN: llvm-objdump -d --no-show-raw-insn --rebase --bind --lazy-bind --weak-bind --full-contents %t/test | \ -# RUN: FileCheck %s +# RUN: llvm-objdump -d --no-show-raw-insn --rebase --bind --lazy-bind \ +# RUN: --weak-bind --full-contents %t/test | FileCheck %s # CHECK: Contents of section __DATA_CONST,__got: ## Check that this section contains a nonzero pointer. It should point to @@ -37,13 +37,15 @@ # CHECK-DAG: __DATA __la_symbol_ptr 0x[[#%x,WEAK_DY_FN:]] pointer 0 libfoo _weak_dysym_fn # CHECK-DAG: __DATA __data 0x[[#%x,WEAK_DY:]] pointer 0 libfoo _weak_dysym # CHECK-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} pointer 0 libSystem __tlv_bootstrap +# CHECK-DAG: __DATA __thread_vars 0x{{[0-9a-f]*}} pointer 0 libSystem __tlv_bootstrap # CHECK-DAG: __DATA __thread_ptrs 0x[[#WEAK_DY_TLV_ADDR]] pointer 0 libfoo _weak_dysym_tlv ## Check that we don't have any other bindings -# CHECK-NOT: pointer +# CHECK-EMPTY: # CHECK-LABEL: Lazy bind table: +# CHECK-NEXT: segment section address dylib symbol ## Verify that we have no lazy bindings -# CHECK-NOT: pointer +# CHECK-EMPTY: # CHECK-LABEL: Weak bind table: # CHECK-DAG: __DATA_CONST __got 0x[[#WEAK_DY_GOT_ADDR]] pointer 0 _weak_dysym_for_gotpcrel @@ -55,7 +57,7 @@ # CHECK-DAG: __DATA __la_symbol_ptr 0x[[#WEAK_DY_FN]] pointer 0 _weak_dysym_fn # CHECK-DAG: __DATA __la_symbol_ptr 0x[[#WEAK_EXT_FN]] pointer 0 _weak_external_fn ## Check that we don't have any other bindings -# CHECK-NOT: pointer +# CHECK-EMPTY: ## Weak internal symbols don't get bindings # RUN: llvm-objdump --macho --bind --lazy-bind --weak-bind %t/test | FileCheck %s --check-prefix=WEAK-INTERNAL