diff --git a/lld/test/wasm/data-segments.ll b/lld/test/wasm/data-segments.ll --- 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 --- a/lld/test/wasm/tls-no-shared.s +++ b/lld/test/wasm/tls-no-shared.s @@ -54,7 +54,7 @@ # 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 @@ # 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.h b/lld/wasm/InputChunks.h --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -108,6 +108,7 @@ 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/InputChunks.cpp b/lld/wasm/InputChunks.cpp --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -353,6 +353,10 @@ 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 @@ 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/MapFile.cpp b/lld/wasm/MapFile.cpp --- a/lld/wasm/MapFile.cpp +++ b/lld/wasm/MapFile.cpp @@ -135,7 +135,7 @@ 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 --- a/lld/wasm/OutputSegment.h +++ b/lld/wasm/OutputSegment.h @@ -22,10 +22,11 @@ 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 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -281,7 +281,7 @@ 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 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -79,6 +79,7 @@ void calculateCustomSections(); void calculateTypes(); void createOutputSegments(); + void combineOutputSegments(); void layoutMemory(); void createHeader(); @@ -88,6 +89,7 @@ void createCustomSections(); void createSyntheticSections(); + void createSyntheticSectionsPostLayout(); void finalizeSections(); // Custom sections @@ -813,10 +815,6 @@ // 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.")) @@ -861,9 +859,9 @@ [](const OutputSegment *a, const OutputSegment *b) { auto order = [](StringRef name) { return StringSwitch(name) - .StartsWith(".rodata", 0) - .StartsWith(".data", 1) - .StartsWith(".tdata", 2) + .StartsWith(".tdata", 0) + .StartsWith(".rodata", 1) + .StartsWith(".data", 2) .StartsWith(".bss", 4) .Default(3); }; @@ -874,6 +872,52 @@ 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 new_segments; + for (OutputSegment *s : segments) { + if (s->name == ".tdata") { + new_segments.push_back(s); + } else { + if (!combined) { + combined = make(".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; { @@ -1313,11 +1357,14 @@ out.exportSec = make(); out.startSec = make(); out.elemSec = make(); + out.producersSec = make(); + out.targetFeaturesSec = make(); +} + +void Writer::createSyntheticSectionsPostLayout() { out.dataCountSec = make(segments); out.linkingSec = make(initFunctions, segments); out.nameSec = make(segments); - out.producersSec = make(); - out.targetFeaturesSec = make(); } void Writer::run() { @@ -1336,18 +1383,17 @@ createOutputSegments(); log("-- createSyntheticSections"); createSyntheticSections(); - log("-- populateProducers"); - populateProducers(); - log("-- calculateImports"); - calculateImports(); log("-- layoutMemory"); + out.memorySec = make(); + out.dylinkSec = make(); 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 @@ -1363,6 +1409,17 @@ warn(Twine("symbol exported via --export not found: ") + name); } + if (config->isPic) + combineOutputSegments(); + + log("-- createSyntheticSectionsPostLayout"); + createSyntheticSectionsPostLayout(); + + log("-- populateProducers"); + populateProducers(); + log("-- calculateImports"); + calculateImports(); + log("-- scanRelocations"); scanRelocations(); log("-- finalizeIndirectFunctionTable");