[WebAssembly] Sort output data sections to place .bss last

Summary:
This was always the intended behavior, but had not been
implemented. This ordering is important for Emscripten when generating
.mem files while compiling to JS, since only zeros at the end of
initialized memory can be dropped.

Fixes https://github.com/emscripten-core/emscripten/issues/8999

Reviewers: sbc100

Subscribers: dschuff, jgravelle-google, aheejin, sunfish, llvm-commits

Tags: #llvm

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

llvm-svn: 372284
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 58d585b..c4a87be 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -263,7 +263,6 @@
     memoryPtr += 4;
   }
 
-  // TODO: Add .bss space here.
   if (WasmSym::dataEnd)
     WasmSym::dataEnd->setVirtualAddress(memoryPtr);
 
@@ -667,7 +666,7 @@
       OutputSegment *&s = segmentMap[name];
       if (s == nullptr) {
         LLVM_DEBUG(dbgs() << "new segment: " << name << "\n");
-        s = make<OutputSegment>(name, segments.size());
+        s = make<OutputSegment>(name);
         if (config->sharedMemory || name == ".tdata")
           s->initFlags = WASM_SEGMENT_IS_PASSIVE;
         segments.push_back(s);
@@ -676,6 +675,24 @@
       LLVM_DEBUG(dbgs() << "added data: " << name << ": " << s->size << "\n");
     }
   }
+
+  // Sort segments by type, placing .bss last
+  std::stable_sort(segments.begin(), segments.end(),
+                   [](const OutputSegment *a, const OutputSegment *b) {
+                     auto order = [](StringRef name) {
+                       return StringSwitch<int>(name)
+                           .StartsWith(".rodata", 0)
+                           .StartsWith(".data", 1)
+                           .StartsWith(".tdata", 2)
+                           .StartsWith(".bss", 4)
+                           .Default(3);
+                     };
+                     return order(a->name) < order(b->name);
+                   });
+
+  for (size_t i = 0; i < segments.size(); ++i) {
+    segments[i]->index = i;
+  }
 }
 
 static void createFunction(DefinedFunction *func, StringRef bodyContent) {