diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index e07f1d74bc..134194068e 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -410,7 +410,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option }, ); } else { - symbol.index = @as(u32, @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len)); + symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); const global = try wasm_bin.wasm_globals.addOne(allocator); global.* = .{ @@ -433,7 +433,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option }; if (options.output_mode == .Obj or options.import_table) { symbol.setUndefined(true); - symbol.index = @as(u32, @intCast(wasm_bin.imported_tables_count)); + symbol.index = @intCast(wasm_bin.imported_tables_count); wasm_bin.imported_tables_count += 1; try wasm_bin.imports.put(allocator, loc, .{ .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), @@ -467,16 +467,31 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option const loc = try wasm_bin.createSyntheticSymbol("__tls_base", .global); const symbol = loc.getSymbol(wasm_bin); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); + symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); + try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + .global_type = .{ .valtype = .i32, .mutable = true }, + .init = .{ .i32_const = undefined }, + }); } { const loc = try wasm_bin.createSyntheticSymbol("__tls_size", .global); const symbol = loc.getSymbol(wasm_bin); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); + symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); + try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + .global_type = .{ .valtype = .i32, .mutable = false }, + .init = .{ .i32_const = undefined }, + }); } { const loc = try wasm_bin.createSyntheticSymbol("__tls_align", .global); const symbol = loc.getSymbol(wasm_bin); symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); + symbol.index = @intCast(wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); + try wasm_bin.wasm_globals.append(wasm_bin.base.allocator, .{ + .global_type = .{ .valtype = .i32, .mutable = false }, + .init = .{ .i32_const = undefined }, + }); } { const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function); @@ -2757,27 +2772,18 @@ fn setupMemory(wasm: *Wasm) !void { if (mem.eql(u8, entry.key_ptr.*, ".tdata")) { if (wasm.findGlobalSymbol("__tls_size")) |loc| { const sym = loc.getSymbol(wasm); - sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; - try wasm.wasm_globals.append(wasm.base.allocator, .{ - .global_type = .{ .valtype = .i32, .mutable = false }, - .init = .{ .i32_const = @as(i32, @intCast(segment.size)) }, - }); + wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size); } if (wasm.findGlobalSymbol("__tls_align")) |loc| { const sym = loc.getSymbol(wasm); - sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; - try wasm.wasm_globals.append(wasm.base.allocator, .{ - .global_type = .{ .valtype = .i32, .mutable = false }, - .init = .{ .i32_const = @as(i32, @intCast(segment.alignment)) }, - }); + wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment); } if (wasm.findGlobalSymbol("__tls_base")) |loc| { const sym = loc.getSymbol(wasm); - sym.index = @as(u32, @intCast(wasm.wasm_globals.items.len)) + wasm.imported_globals_count; - try wasm.wasm_globals.append(wasm.base.allocator, .{ - .global_type = .{ .valtype = .i32, .mutable = wasm.base.options.shared_memory }, - .init = .{ .i32_const = if (wasm.base.options.shared_memory) @as(u32, 0) else @as(i32, @intCast(memory_ptr)) }, - }); + wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (wasm.base.options.shared_memory) + @as(i32, 0) + else + @as(i32, @intCast(memory_ptr)); } } diff --git a/test/link/wasm/shared-memory/build.zig b/test/link/wasm/shared-memory/build.zig index 7107ad1c4e..cf84ad7528 100644 --- a/test/link/wasm/shared-memory/build.zig +++ b/test/link/wasm/shared-memory/build.zig @@ -5,11 +5,9 @@ pub fn build(b: *std.Build) void { b.default_step = test_step; add(b, test_step, .Debug); - - // Enable the following build modes once garbage-collection is implemented properly. - // add(b, test_step, .ReleaseFast); - // add(b, test_step, .ReleaseSmall); - // add(b, test_step, .ReleaseSafe); + add(b, test_step, .ReleaseFast); + add(b, test_step, .ReleaseSmall); + add(b, test_step, .ReleaseSafe); } fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void { @@ -47,30 +45,53 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt // This section *must* be emit as the start function is set to the index // of __wasm_init_memory - check_lib.checkStart("Section start"); + // release modes will have the TLS segment optimized out in our test-case. + // This means we won't have __wasm_init_memory in such case, and therefore + // should also not have a section "start" + if (optimize_mode == .Debug) { + check_lib.checkStart("Section start"); + } // This section is only and *must* be emit when shared-memory is enabled - check_lib.checkStart("Section data_count"); - check_lib.checkNext("count 3"); + // release modes will have the TLS segment optimized out in our test-case. + if (optimize_mode == .Debug) { + check_lib.checkStart("Section data_count"); + check_lib.checkNext("count 3"); + } check_lib.checkStart("Section custom"); check_lib.checkNext("name name"); check_lib.checkNext("type function"); - check_lib.checkNext("name __wasm_init_memory"); + if (optimize_mode == .Debug) { + check_lib.checkNext("name __wasm_init_memory"); + } check_lib.checkNext("name __wasm_init_tls"); check_lib.checkNext("type global"); - check_lib.checkNext("name __tls_size"); - check_lib.checkNext("name __tls_align"); - check_lib.checkNext("name __tls_base"); + + // In debug mode the symbol __tls_base is resolved to an undefined symbol + // from the object file, hence its placement differs than in release modes + // where the entire tls segment is optimized away, and tls_base will have + // its original position. + if (optimize_mode == .Debug) { + check_lib.checkNext("name __tls_size"); + check_lib.checkNext("name __tls_align"); + check_lib.checkNext("name __tls_base"); + } else { + check_lib.checkNext("name __tls_base"); + check_lib.checkNext("name __tls_size"); + check_lib.checkNext("name __tls_align"); + } check_lib.checkNext("type data_segment"); - check_lib.checkNext("names 3"); - check_lib.checkNext("index 0"); - check_lib.checkNext("name .rodata"); - check_lib.checkNext("index 1"); - check_lib.checkNext("name .bss"); - check_lib.checkNext("index 2"); - check_lib.checkNext("name .tdata"); + if (optimize_mode == .Debug) { + check_lib.checkNext("names 3"); + check_lib.checkNext("index 0"); + check_lib.checkNext("name .rodata"); + check_lib.checkNext("index 1"); + check_lib.checkNext("name .bss"); + check_lib.checkNext("index 2"); + check_lib.checkNext("name .tdata"); + } test_step.dependOn(&check_lib.step); }