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 @@ -107,7 +107,7 @@ ; PASSIVE-PIC: - Type: START ; PASSIVE-PIC-NEXT: StartFunction: 2 ; PASSIVE-PIC-NEXT: - Type: DATACOUNT -; PASSIVE-PIC-NEXT: Count: 1 +; PASSIVE-PIC-NEXT: Count: 2 ; PASSIVE-PIC-NEXT: - Type: CODE ; PASSIVE-PIC-NEXT: Functions: ; PASSIVE-PIC-NEXT: - Index: 0 @@ -121,14 +121,14 @@ ; PASSIVE32-PIC-NEXT: - Type: I32 ; PASSIVE64-PIC-NEXT: - Type: I64 ; PASSIVE-PIC-NEXT: Count: 1 -; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B -; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A410041B4CE00FC08000020004102FE1702002000417FFE0002001A0BFC09000B +; PASSIVE32-PIC-NEXT: Body: 230141B4CE006A2100200041004101FE480200044020004101427FFE0102001A05410023016A4100410DFC080000411023016A41004114FC08010020004102FE1702002000417FFE0002001A0BFC0900FC09010B +; PASSIVE64-PIC-NEXT: Body: 230142B4CE006A2100200041004101FE480200044020004101427FFE0102001A05420023016A4100410DFC080000421023016A41004114FC08010020004102FE1702002000417FFE0002001A0BFC0900FC09010B ; PASSIVE-PIC-NEXT: - Index: 3 ; PASSIVE-PIC-NEXT: Locals: [] ; PASSIVE-PIC-NEXT: Body: 0B ; PASSIVE-PIC-NEXT: - Type: DATA ; PASSIVE-PIC-NEXT: Segments: -; PASSIVE-PIC-NEXT: - SectionOffset: 4 +; PASSIVE-PIC-NEXT: - SectionOffset: 3 ; PASSIVE-PIC-NEXT: InitFlags: 1 ; PASSIVE-PIC: - Type: CUSTOM diff --git a/lld/test/wasm/relocation-bad-tls.s b/lld/test/wasm/relocation-bad-tls.s --- a/lld/test/wasm/relocation-bad-tls.s +++ b/lld/test/wasm/relocation-bad-tls.s @@ -1,5 +1,5 @@ # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s -# RUN: not wasm-ld %t.o -o %t.wasm 2>&1 | FileCheck %s +# RUN: not wasm-ld --shared-memory %t.o -o %t.wasm 2>&1 | FileCheck %s .globl _start _start: diff --git a/lld/test/wasm/tls-no-shared.s b/lld/test/wasm/tls-non-shared-memory.s rename from lld/test/wasm/tls-no-shared.s rename to lld/test/wasm/tls-non-shared-memory.s --- a/lld/test/wasm/tls-no-shared.s +++ b/lld/test/wasm/tls-non-shared-memory.s @@ -9,7 +9,7 @@ get_tls1: .functype get_tls1 () -> (i32) global.get __tls_base - i32.const tls1 + i32.const tls1@TLSREL i32.add end_function @@ -39,6 +39,9 @@ # RUN: wasm-ld --no-gc-sections --no-entry -o %t.wasm %t.o # RUN: obj2yaml %t.wasm | FileCheck %s +# RUN: wasm-ld --experimental-pic -shared -o %t.so %t.o +# RUN: obj2yaml %t.so | FileCheck %s --check-prefix=PIC + # CHECK: - Type: GLOBAL # __stack_pointer # CHECK-NEXT: Globals: @@ -73,3 +76,27 @@ # CHECK-NEXT: Opcode: I32_CONST # CHECK-NEXT: Value: 1028 # CHECK-NEXT: Content: 2A000000 + +# In PIC mode we expect TLS data and non-TLS data to be merged into +# a single segment which is initialized via the __memory_base import + +# PIC: - Type: IMPORT +# PIC-NEXT: Imports: +# PIC-NEXT: - Module: env +# PIC-NEXT: Field: memory +# PIC-NEXT: Kind: MEMORY +# PIC-NEXT: Memory: +# PIC-NEXT: Minimum: 0x1 +# PIC-NEXT: - Module: env +# PIC-NEXT: Field: __memory_base +# PIC-NEXT: Kind: GLOBAL +# PIC-NEXT: GlobalType: I32 + +# PIC: - Type: DATA +# PIC-NEXT: Segments: +# PIC-NEXT: - SectionOffset: 6 +# PIC-NEXT: InitFlags: 0 +# PIC-NEXT: Offset: +# PIC-NEXT: Opcode: GLOBAL_GET +# PIC-NEXT: Index: 0 +# PIC-NEXT: Content: 2B0000002A000000 diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp --- a/lld/wasm/OutputSections.cpp +++ b/lld/wasm/OutputSections.cpp @@ -144,8 +144,8 @@ }); #endif - assert((!config->isPic || activeCount <= 1) && - "Currenly only a single data segment is supported in PIC mode"); + assert((config->sharedMemory || !config->isPic || activeCount <= 1) && + "output segments should have been combined by now"); writeUleb128(os, segmentCount, "data segment count"); os.flush(); diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp --- a/lld/wasm/Relocations.cpp +++ b/lld/wasm/Relocations.cpp @@ -115,12 +115,17 @@ addGOTEntry(sym); break; case R_WASM_MEMORY_ADDR_TLS_SLEB: - if (auto *D = dyn_cast(sym)) { - if (!D->segment->outputSeg->isTLS()) { - error(toString(file) + ": relocation " + - relocTypeToString(reloc.Type) + " cannot be used against `" + - toString(*sym) + - "` in non-TLS section: " + D->segment->outputSeg->name); + // In single-threaded builds TLS is lowered away and TLS data can be + // merged with normal data and allowing TLS relocation in non-TLS + // segments. + if (config->sharedMemory) { + if (auto *D = dyn_cast(sym)) { + if (!D->segment->outputSeg->isTLS()) { + error(toString(file) + ": relocation " + + relocTypeToString(reloc.Type) + " cannot be used against `" + + toString(*sym) + + "` in non-TLS section: " + D->segment->outputSeg->name); + } } } break; diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -895,53 +895,37 @@ } 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. + // With PIC code we currently only support a single active data segment since + // we only have a single __memory_base to use as our base address. This pass + // combines all 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); + assert(config->isPic && !config->sharedMemory); if (segments.size() <= 1) return; - OutputSegment *combined = nullptr; - std::vector new_segments; + OutputSegment *combined = make(".data"); + combined->startVA = segments[0]->startVA; for (OutputSegment *s : segments) { - if (s->isTLS()) { - new_segments.push_back(s); - } else { - if (!combined) { - LLVM_DEBUG(dbgs() << "created combined output segment: .data\n"); - combined = make(".data"); - combined->startVA = s->startVA; - if (config->sharedMemory) - combined->initFlags = WASM_DATA_SEGMENT_IS_PASSIVE; - } - bool first = true; - for (InputChunk *inSeg : s->inputSegments) { - if (first) - inSeg->alignment = std::max(inSeg->alignment, s->alignment); - first = false; + bool first = true; + for (InputChunk *inSeg : s->inputSegments) { + if (first) + inSeg->alignment = std::max(inSeg->alignment, s->alignment); + first = false; #ifndef NDEBUG - uint64_t oldVA = inSeg->getVA(); + uint64_t oldVA = inSeg->getVA(); #endif - combined->addInputSegment(inSeg); + combined->addInputSegment(inSeg); #ifndef NDEBUG - uint64_t newVA = inSeg->getVA(); - LLVM_DEBUG(dbgs() << "added input segment. name=" << inSeg->getName() - << " oldVA=" << oldVA << " newVA=" << newVA << "\n"); - assert(oldVA == newVA); + uint64_t newVA = inSeg->getVA(); + LLVM_DEBUG(dbgs() << "added input segment. name=" << inSeg->getName() + << " oldVA=" << oldVA << " newVA=" << newVA << "\n"); + 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; - } + + segments = {combined}; } static void createFunction(DefinedFunction *func, StringRef bodyContent) { @@ -1440,7 +1424,9 @@ } } - if (config->isPic) { + if (config->isPic && !config->sharedMemory) { + // In shared memory mode all data segments are passive and initilized + // via __wasm_init_memory. log("-- combineOutputSegments"); combineOutputSegments(); }