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 <limits>
+
 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<int>::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 <limits>
+
 namespace lld {
 namespace macho {
 
@@ -42,7 +44,7 @@
   void addOutputSection(OutputSection *os);
   void sortOutputSections(
       llvm::function_ref<bool(OutputSection *, OutputSection *)> comparator) {
-    llvm::stable_sort(sections, comparator);
+    llvm::sort(sections, comparator);
   }
 
   const std::vector<OutputSection *> &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<int>::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<int>::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<int>::max() - 1)
         .Case(section_names::ehFrame, std::numeric_limits<int>::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<int>::max();
     default:
       return StringSwitch<int>(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<int>(osec->name)
@@ -814,13 +815,13 @@
         .Case(section_names::indirectSymbolTable, -2)
         .Case(section_names::stringTable, -1)
         .Case(section_names::codeSignature, std::numeric_limits<int>::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<int>::max();
-  return 0;
+  return osec->inputOrder;
 }
 
 template <typename T, typename F>
@@ -834,8 +835,7 @@
 static void sortSegmentsAndSections() {
   TimeTraceScope timeScope("Sort segments and sections");
 
-  llvm::stable_sort(outputSegments,
-                    compareByOrder<OutputSegment *>(segmentOrder));
+  llvm::sort(outputSegments, compareByOrder<OutputSegment *>(segmentOrder));
 
   DenseMap<const InputSection *, size_t> isecPriorities =
       buildInputSectionPriorities();
@@ -898,14 +898,17 @@
   }
 
   // Then add input sections to output sections.
-  MapVector<NamePair, ConcatOutputSection *> concatOutputSections;
-  for (InputSection *isec : inputSections) {
+  DenseMap<NamePair, ConcatOutputSection *> 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<ConcatOutputSection>(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