[lld] 70f3c6e - [lld][WebAssembly] Delay the merging of data section when dynamic linking

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 11 10:54:27 PST 2021


Author: Sam Clegg
Date: 2021-02-11T10:54:15-08:00
New Revision: 70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536

URL: https://github.com/llvm/llvm-project/commit/70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536
DIFF: https://github.com/llvm/llvm-project/commit/70f3c6e9e6b8a0e5efc7cbf8997df32156ea9536.diff

LOG: [lld][WebAssembly] Delay the merging of data section when dynamic linking

With dynamic linking we have the current limitation that there can be
only a single active data segment (since we use __memory_base as the
load address and we can't do arithmetic in constant expresions).

This change delays the merging of active segments until a little later
in the linking process which means that the grouping of data by section,
and the magic __start/__end symbols work as expected under dynamic
linking.

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

Added: 
    

Modified: 
    lld/test/wasm/data-segments.ll
    lld/test/wasm/tls-no-shared.s
    lld/wasm/InputChunks.cpp
    lld/wasm/InputChunks.h
    lld/wasm/MapFile.cpp
    lld/wasm/OutputSegment.h
    lld/wasm/Symbols.cpp
    lld/wasm/Writer.cpp

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll
index 1af6dccce457..9c0382c693d2 100644
--- a/lld/test/wasm/data-segments.ll
+++ b/lld/test/wasm/data-segments.ll
@@ -121,8 +121,8 @@
 ; PASSIVE32-PIC-NEXT:          - Type:            I32
 ; PASSIVE64-PIC-NEXT:          - Type:            I64
 ; PASSIVE-PIC-NEXT:            Count:           1
-; PASSIVE32-PIC-NEXT:        Body:            230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
-; PASSIVE64-PIC-NEXT:        Body:            230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B1CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
+; PASSIVE32-PIC-NEXT:        Body:            230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
+; PASSIVE64-PIC-NEXT:        Body:            230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B
 ; PASSIVE-PIC-NEXT:      - Index:           3
 ; PASSIVE-PIC-NEXT:        Locals:          []
 ; PASSIVE-PIC-NEXT:        Body:            0B

diff  --git a/lld/test/wasm/tls-no-shared.s b/lld/test/wasm/tls-no-shared.s
index 6c17489b7d42..d93a19c84338 100644
--- a/lld/test/wasm/tls-no-shared.s
+++ b/lld/test/wasm/tls-no-shared.s
@@ -54,7 +54,7 @@ tls1:
 # CHECK-NEXT:         Mutable:         false
 # CHECK-NEXT:         InitExpr:
 # CHECK-NEXT:           Opcode:          I32_CONST
-# CHECK-NEXT:           Value:           1028
+# CHECK-NEXT:           Value:           1024
 # CHECK-NEXT:   - Type:            EXPORT
 
 #      CHECK:  - Type:            DATA
@@ -65,11 +65,11 @@ tls1:
 # CHECK-NEXT:        Offset:
 # CHECK-NEXT:          Opcode:          I32_CONST
 # CHECK-NEXT:          Value:           1024
-# CHECK-NEXT:        Content:         2A000000
+# CHECK-NEXT:        Content:         2B000000
 # .tdata
 # CHECK-NEXT:      - SectionOffset:   17
 # CHECK-NEXT:        InitFlags:       0
 # CHECK-NEXT:        Offset:
 # CHECK-NEXT:          Opcode:          I32_CONST
 # CHECK-NEXT:          Value:           1028
-# CHECK-NEXT:        Content:         2B000000
+# CHECK-NEXT:        Content:         2A000000

diff  --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index d8c5f84c0487..d90342491e34 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -353,6 +353,10 @@ void InputFunction::writeTo(uint8_t *buf) const {
   LLVM_DEBUG(dbgs() << "  total: " << (buf + chunkSize - orig) << "\n");
 }
 
+uint64_t InputSegment::getVA() const {
+  return outputSeg->startVA + outputSegmentOffset;
+}
+
 // Generate code to apply relocations to the data section at runtime.
 // This is only called when generating shared libaries (PIC) where address are
 // not known at static link time.
@@ -370,10 +374,9 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
   auto tombstone = getTombstone();
   // TODO(sbc): Encode the relocations in the data section and write a loop
   // here to apply them.
-  uint64_t segmentVA = outputSeg->startVA + outputSegmentOffset;
   for (const WasmRelocation &rel : relocations) {
     uint64_t offset = rel.Offset - getInputSectionOffset();
-    uint64_t outputOffset = segmentVA + offset;
+    uint64_t outputOffset = getVA() + offset;
 
     LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type)
                       << " addend=" << rel.Addend << " index=" << rel.Index

diff  --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 9082d1dada5f..e237888cf480 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -108,6 +108,7 @@ class InputSegment : public InputChunk {
   uint32_t getInputSectionOffset() const override {
     return segment.SectionOffset;
   }
+  uint64_t getVA() const;
 
   const OutputSegment *outputSeg = nullptr;
   int32_t outputSegmentOffset = 0;

diff  --git a/lld/wasm/MapFile.cpp b/lld/wasm/MapFile.cpp
index c6f08b785413..e1497aa6e0ee 100644
--- a/lld/wasm/MapFile.cpp
+++ b/lld/wasm/MapFile.cpp
@@ -138,7 +138,7 @@ void lld::wasm::writeMapFile(ArrayRef<OutputSection *> outputSections) {
                     oseg->size);
         os << oseg->name << '\n';
         for (auto *chunk : oseg->inputSegments) {
-          writeHeader(os, oseg->startVA + chunk->outputSegmentOffset,
+          writeHeader(os, chunk->getVA(),
                       chunk->outputSec->getOffset() + chunk->outputOffset,
                       chunk->getSize());
           os.indent(8) << toString(chunk) << '\n';

diff  --git a/lld/wasm/OutputSegment.h b/lld/wasm/OutputSegment.h
index 34c3c49ff796..f6985ce855e6 100644
--- a/lld/wasm/OutputSegment.h
+++ b/lld/wasm/OutputSegment.h
@@ -22,10 +22,11 @@ class OutputSegment {
 public:
   OutputSegment(StringRef n) : name(n) {}
 
-  void addInputSegment(InputSegment *inSeg) {
-    alignment = std::max(alignment, inSeg->getAlignment());
+  void addInputSegment(InputSegment *inSeg, uint32_t forceAlignment = 0) {
+    uint32_t segAlign = std::max(forceAlignment, inSeg->getAlignment());
+    alignment = std::max(alignment, segAlign);
     inputSegments.push_back(inSeg);
-    size = llvm::alignTo(size, 1ULL << inSeg->getAlignment());
+    size = llvm::alignTo(size, 1ULL << segAlign);
     inSeg->outputSeg = this;
     inSeg->outputSegmentOffset = size;
     size += inSeg->getSize();

diff  --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index 6db1fa944ffc..269357921589 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -279,7 +279,7 @@ DefinedFunction::DefinedFunction(StringRef name, uint32_t flags, InputFile *f,
 uint64_t DefinedData::getVirtualAddress() const {
   LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
   if (segment)
-    return segment->outputSeg->startVA + segment->outputSegmentOffset + offset;
+    return segment->getVA() + offset;
   return offset;
 }
 

diff  --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index be35f7a6d146..d91b6b811081 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -77,6 +77,7 @@ class Writer {
   void calculateCustomSections();
   void calculateTypes();
   void createOutputSegments();
+  void combineOutputSegments();
   void layoutMemory();
   void createHeader();
 
@@ -86,6 +87,7 @@ class Writer {
 
   void createCustomSections();
   void createSyntheticSections();
+  void createSyntheticSectionsPostLayout();
   void finalizeSections();
 
   // Custom sections
@@ -795,10 +797,6 @@ static StringRef getOutputDataSegmentName(StringRef name) {
   // We also need to merge .tbss into .tdata so they share the same offsets.
   if (name.startswith(".tdata") || name.startswith(".tbss"))
     return ".tdata";
-  // With PIC code we currently only support a single data segment since
-  // we only have a single __memory_base to use as our base address.
-  if (config->isPic)
-    return ".data";
   if (!config->mergeDataSegments)
     return name;
   if (name.startswith(".text."))
@@ -843,9 +841,9 @@ void Writer::createOutputSegments() {
                    [](const OutputSegment *a, const OutputSegment *b) {
                      auto order = [](StringRef name) {
                        return StringSwitch<int>(name)
-                           .StartsWith(".rodata", 0)
-                           .StartsWith(".data", 1)
-                           .StartsWith(".tdata", 2)
+                           .StartsWith(".tdata", 0)
+                           .StartsWith(".rodata", 1)
+                           .StartsWith(".data", 2)
                            .StartsWith(".bss", 4)
                            .Default(3);
                      };
@@ -856,6 +854,52 @@ void Writer::createOutputSegments() {
     segments[i]->index = i;
 }
 
+void Writer::combineOutputSegments() {
+  // With PIC code we currently only support a single data segment since
+  // we only have a single __memory_base to use as our base address.
+  // This pass combines all non-TLS data segments into a single .data
+  // segment.
+  // This restructions can be relaxed once we have extended constant
+  // expressions available:
+  // https://github.com/WebAssembly/extended-const
+  assert(config->isPic);
+  if (segments.size() <= 1)
+    return;
+  OutputSegment *combined = nullptr;
+  std::vector<OutputSegment *> new_segments;
+  for (OutputSegment *s : segments) {
+    if (s->name == ".tdata") {
+      new_segments.push_back(s);
+    } else {
+      if (!combined) {
+        combined = make<OutputSegment>(".data");
+        combined->startVA = s->startVA;
+        if (config->sharedMemory)
+          combined->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE;
+      }
+      bool first = true;
+      for (InputSegment *inSeg : s->inputSegments) {
+        uint32_t alignment = first ? s->alignment : 0;
+        first = false;
+#ifndef NDEBUG
+        uint64_t oldVA = inSeg->getVA();
+#endif
+        combined->addInputSegment(inSeg, alignment);
+#ifndef NDEBUG
+        uint64_t newVA = inSeg->getVA();
+        assert(oldVA == newVA);
+#endif
+      }
+    }
+  }
+  if (combined) {
+    new_segments.push_back(combined);
+    segments = new_segments;
+    for (size_t i = 0; i < segments.size(); ++i)
+      segments[i]->index = i;
+  }
+}
+
 static void createFunction(DefinedFunction *func, StringRef bodyContent) {
   std::string functionBody;
   {
@@ -1295,11 +1339,14 @@ void Writer::createSyntheticSections() {
   out.exportSec = make<ExportSection>();
   out.startSec = make<StartSection>();
   out.elemSec = make<ElemSection>();
+  out.producersSec = make<ProducersSection>();
+  out.targetFeaturesSec = make<TargetFeaturesSection>();
+}
+
+void Writer::createSyntheticSectionsPostLayout() {
   out.dataCountSec = make<DataCountSection>(segments);
   out.linkingSec = make<LinkingSection>(initFunctions, segments);
   out.nameSec = make<NameSection>(segments);
-  out.producersSec = make<ProducersSection>();
-  out.targetFeaturesSec = make<TargetFeaturesSection>();
 }
 
 void Writer::run() {
@@ -1318,18 +1365,15 @@ void Writer::run() {
   createOutputSegments();
   log("-- createSyntheticSections");
   createSyntheticSections();
-  log("-- populateProducers");
-  populateProducers();
-  log("-- calculateImports");
-  calculateImports();
   log("-- layoutMemory");
   layoutMemory();
 
   if (!config->relocatable) {
     // Create linker synthesized __start_SECNAME/__stop_SECNAME symbols
     // This has to be done after memory layout is performed.
-    for (const OutputSegment *seg : segments)
+    for (const OutputSegment *seg : segments) {
       addStartStopSymbols(seg);
+    }
   }
 
   // Delay reporting error about explict exports until after addStartStopSymbols
@@ -1345,6 +1389,17 @@ void Writer::run() {
       warn(Twine("symbol exported via --export not found: ") + name);
   }
 
+  if (config->isPic) {
+    log("-- combineOutputSegments");
+    combineOutputSegments();
+  }
+
+  log("-- createSyntheticSectionsPostLayout");
+  createSyntheticSectionsPostLayout();
+  log("-- populateProducers");
+  populateProducers();
+  log("-- calculateImports");
+  calculateImports();
   log("-- scanRelocations");
   scanRelocations();
   log("-- finalizeIndirectFunctionTable");


        


More information about the llvm-commits mailing list