authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 18:17:37-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 18:17:37-08:00
log9dd6efb7e422ddc54ca34dc76b0d9efab746f8bf
tree0b83a8901a3bc0efff2f92084cb4519842e58980
parent10db1b9eda849420b92cc21e2cbc93e0c74740bb

wasm linker: fix TLS data segments

fix calculation of alignment and size include __tls_align and __tls_size globals along with __tls_base include them only if the TLS segment is emitted add missing reloc logic for memory_addr_tls_sleb fix name of data segments to include only the prefix

2 files changed, 39 insertions(+), 25 deletions(-)

src/link/Wasm/Flush.zig+38-25
......@@ -330,16 +330,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
330330 try wasm.addFunction(.__wasm_init_memory, &.{}, &.{});
331331 }
332332
333 // When we have TLS GOT entries and shared memory is enabled,
334 // we must perform runtime relocations or else we don't create the function.
335 if (shared_memory) {
336 // This logic that checks `any_tls_relocs` is missing the part where it
337 // also notices threadlocal globals from Zcu code.
338 if (wasm.any_tls_relocs) try wasm.addFunction(.__wasm_apply_global_tls_relocs, &.{}, &.{});
339 try wasm.addFunction(.__wasm_init_tls, &.{.i32}, &.{});
340 try wasm.globals.put(gpa, .__tls_base, {});
341 }
342
343333 try wasm.tables.ensureUnusedCapacity(gpa, 1);
344334
345335 if (f.indirect_function_table.entries.len > 0) {
......@@ -446,17 +436,25 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
446436 const want_new_segment = b: {
447437 if (is_obj) break :b false;
448438 switch (seen_tls) {
449 .before => if (category == .tls) {
450 virtual_addrs.tls_base = if (shared_memory) 0 else @intCast(start_addr);
451 virtual_addrs.tls_align = alignment;
452 seen_tls = .during;
453 break :b f.data_segment_groups.items.len > 0;
439 .before => switch (category) {
440 .tls => {
441 virtual_addrs.tls_base = if (shared_memory) 0 else @intCast(start_addr);
442 virtual_addrs.tls_align = alignment;
443 seen_tls = .during;
444 break :b f.data_segment_groups.items.len > 0;
445 },
446 else => {},
454447 },
455 .during => if (category != .tls) {
456 virtual_addrs.tls_size = @intCast(start_addr - virtual_addrs.tls_base.?);
457 virtual_addrs.tls_align = virtual_addrs.tls_align.maxStrict(alignment);
458 seen_tls = .after;
459 break :b true;
448 .during => switch (category) {
449 .tls => {
450 virtual_addrs.tls_align = virtual_addrs.tls_align.maxStrict(alignment);
451 virtual_addrs.tls_size = @intCast(memory_ptr - virtual_addrs.tls_base.?);
452 break :b false;
453 },
454 else => {
455 seen_tls = .after;
456 break :b true;
457 },
460458 },
461459 .after => {},
462460 }
......@@ -480,6 +478,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
480478 .first_segment = first_segment,
481479 .end_addr = @intCast(memory_ptr),
482480 });
481 if (category == .tls and seen_tls == .during) {
482 virtual_addrs.tls_size = @intCast(memory_ptr - virtual_addrs.tls_base.?);
483 }
483484 }
484485
485486 if (shared_memory and wasm.any_passive_inits) {
......@@ -537,6 +538,19 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
537538 }
538539 f.memory_layout_finished = true;
539540
541 // When we have TLS GOT entries and shared memory is enabled, we must
542 // perform runtime relocations or else we don't create the function.
543 if (shared_memory and virtual_addrs.tls_base != null) {
544 // This logic that checks `any_tls_relocs` is missing the part where it
545 // also notices threadlocal globals from Zcu code.
546 if (wasm.any_tls_relocs) try wasm.addFunction(.__wasm_apply_global_tls_relocs, &.{}, &.{});
547 try wasm.addFunction(.__wasm_init_tls, &.{.i32}, &.{});
548 try wasm.globals.ensureUnusedCapacity(gpa, 3);
549 wasm.globals.putAssumeCapacity(.__tls_base, {});
550 wasm.globals.putAssumeCapacity(.__tls_size, {});
551 wasm.globals.putAssumeCapacity(.__tls_align, {});
552 }
553
540554 var section_index: u32 = 0;
541555 // Index of the code section. Used to tell relocation table where the section lives.
542556 var code_section_index: ?u32 = null;
......@@ -986,9 +1000,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
9861000 }
9871001 segment_offset += @intCast(binary_bytes.items.len - code_start);
9881002 }
989 assert(group_index == f.data_segment_groups.items.len);
9901003
991 replaceVecSectionHeader(binary_bytes, header_offset, .data, group_index);
1004 replaceVecSectionHeader(binary_bytes, header_offset, .data, @intCast(f.data_segment_groups.items.len));
9921005 data_section_index = section_index;
9931006 section_index += 1;
9941007 }
......@@ -1128,7 +1141,7 @@ fn emitNameSection(
11281141 try leb.writeUleb128(binary_bytes.writer(gpa), total_data_segments);
11291142
11301143 for (data_segment_groups, 0..) |group, i| {
1131 const name = group.first_segment.name(wasm);
1144 const name, _ = splitSegmentName(group.first_segment.name(wasm));
11321145 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i)));
11331146 try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
11341147 try binary_bytes.appendSlice(gpa, name);
......@@ -1680,8 +1693,8 @@ fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.Itera
16801693 .memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"),
16811694 .memory_addr_sleb => reloc_sleb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
16821695 .memory_addr_sleb64 => reloc_sleb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1683 .memory_addr_tls_sleb => @panic("TODO implement relocation memory_addr_tls_sleb"),
1684 .memory_addr_tls_sleb64 => @panic("TODO implement relocation memory_addr_tls_sleb64"),
1696 .memory_addr_tls_sleb => reloc_sleb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1697 .memory_addr_tls_sleb64 => reloc_sleb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
16851698
16861699 .memory_addr_import_i32 => reloc_u32_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
16871700 .memory_addr_import_i64 => reloc_u64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
test/link/wasm/shared-memory/build.zig+1
......@@ -43,6 +43,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt
4343 check_exe.checkInHeaders();
4444 check_exe.checkExact("Section export");
4545 check_exe.checkExact("entries 2");
46 check_exe.checkExact("name foo");
4647 check_exe.checkExact("name memory"); // ensure we also export memory again
4748
4849 // This section *must* be emit as the start function is set to the index