diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 5c24d53722..0c74a4e40e 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -1012,6 +1012,10 @@ const WasmDumper = struct { const start = try std.leb.readULEB128(u32, reader); try writer.print("\nstart {d}\n", .{start}); }, + .data_count => { + const count = try std.leb.readULEB128(u32, reader); + try writer.print("\ncount {d}\n", .{count}); + }, else => {}, // skip unknown sections } } @@ -1143,9 +1147,16 @@ const WasmDumper = struct { .data => { var i: u32 = 0; while (i < entries) : (i += 1) { - const index = try std.leb.readULEB128(u32, reader); + const flags = try std.leb.readULEB128(u32, reader); + const index = if (flags & 0x02 != 0) + try std.leb.readULEB128(u32, reader) + else + 0; try writer.print("memory index 0x{x}\n", .{index}); - try parseDumpInit(step, reader, writer); + if (flags == 0) { + try parseDumpInit(step, reader, writer); + } + const size = try std.leb.readULEB128(u32, reader); try writer.print("size {d}\n", .{size}); try reader.skipBytes(size, .{}); // we do not care about the content of the segments @@ -1174,7 +1185,7 @@ const WasmDumper = struct { } fn parseDumpInit(step: *Step, reader: anytype, writer: anytype) !void { - const byte = try std.leb.readULEB128(u8, reader); + const byte = try reader.readByte(); const opcode = std.meta.intToEnum(std.wasm.Opcode, byte) catch { return step.fail("invalid wasm opcode '{d}'", .{byte}); }; diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index c83f72328c..22e88a0d71 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -65,6 +65,7 @@ sanitize_thread: bool, rdynamic: bool, dwarf_format: ?std.dwarf.Format = null, import_memory: bool = false, +export_memory: bool = false, /// For WebAssembly targets, this will allow for undefined symbols to /// be imported from the host environment. import_symbols: bool = false, @@ -1662,6 +1663,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { if (self.import_memory) { try zig_args.append("--import-memory"); } + if (self.export_memory) { + try zig_args.append("--export-memory"); + } if (self.import_symbols) { try zig_args.append("--import-symbols"); } diff --git a/test/link/wasm/shared-memory/build.zig b/test/link/wasm/shared-memory/build.zig new file mode 100644 index 0000000000..7107ad1c4e --- /dev/null +++ b/test/link/wasm/shared-memory/build.zig @@ -0,0 +1,77 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test"); + 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); +} + +fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.OptimizeMode) void { + { + const lib = b.addSharedLibrary(.{ + .name = "lib", + .root_source_file = .{ .path = "lib.zig" }, + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, + .cpu_features_add = std.Target.wasm.featureSet(&.{ .atomics, .bulk_memory }), + .os_tag = .freestanding, + }, + .optimize = optimize_mode, + }); + lib.use_lld = false; + lib.strip = false; + lib.import_memory = true; + lib.export_memory = true; + lib.shared_memory = true; + lib.max_memory = 67108864; + lib.single_threaded = false; + lib.export_symbol_names = &.{"foo"}; + + const check_lib = lib.checkObject(); + + check_lib.checkStart("Section import"); + check_lib.checkNext("entries 1"); + check_lib.checkNext("module env"); + check_lib.checkNext("name memory"); // ensure we are importing memory + + check_lib.checkStart("Section export"); + check_lib.checkNext("entries 2"); + check_lib.checkNext("name memory"); // ensure we also export memory again + + // This section *must* be emit as the start function is set to the index + // of __wasm_init_memory + 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"); + + check_lib.checkStart("Section custom"); + check_lib.checkNext("name name"); + check_lib.checkNext("type function"); + 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"); + + 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"); + + test_step.dependOn(&check_lib.step); + } +} diff --git a/test/link/wasm/shared-memory/lib.zig b/test/link/wasm/shared-memory/lib.zig new file mode 100644 index 0000000000..714babb16c --- /dev/null +++ b/test/link/wasm/shared-memory/lib.zig @@ -0,0 +1,5 @@ +threadlocal var some_tls_global: u32 = 1; + +export fn foo() void { + some_tls_global = 2; +}