authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-14 18:23:38-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
logb37ad5110cb66330211e930df1d1093963213c48
tree9927c40937719df863caf5eec90ccfab744c4c9e
parentc535422423abc0258b03693392bae86560a9cc79

wasm linker: always passive when importing memory

and detect passive inits from Zcu don't forget to intern function type for __wasm_init_memory make that function the start function if it is present don't skip emitting passive data segment data to the binary

2 files changed, 18 insertions(+), 7 deletions(-)

src/link/Wasm.zig+5-2
...@@ -1968,7 +1968,7 @@ pub const DataSegmentId = enum(u32) {...@@ -1968,7 +1968,7 @@ pub const DataSegmentId = enum(u32) {
19681968
1969 pub fn isPassive(id: DataSegmentId, wasm: *const Wasm) bool {1969 pub fn isPassive(id: DataSegmentId, wasm: *const Wasm) bool {
1970 const comp = wasm.base.comp;1970 const comp = wasm.base.comp;
1971 if (comp.config.import_memory and !id.isBss(wasm)) return true;1971 if (comp.config.import_memory) return true;
1972 return switch (unpack(id, wasm)) {1972 return switch (unpack(id, wasm)) {
1973 .__zig_error_names,1973 .__zig_error_names,
1974 .__zig_error_name_table,1974 .__zig_error_name_table,
...@@ -4614,7 +4614,10 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu...@@ -4614,7 +4614,10 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu
4614 .off = .none,4614 .off = .none,
4615 .len = naive_code.len,4615 .len = naive_code.len,
4616 };4616 };
4617 } else naive_code;4617 } else c: {
4618 wasm.any_passive_inits = wasm.any_passive_inits or wasm.base.comp.config.import_memory;
4619 break :c naive_code;
4620 };
46184621
4619 return .{4622 return .{
4620 .code = code,4623 .code = code,
src/link/Wasm/Flush.zig+13-5
...@@ -282,6 +282,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -282,6 +282,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
282 // function.282 // function.
283 if (wasm.any_passive_inits) {283 if (wasm.any_passive_inits) {
284 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});284 wasm.functions.putAssumeCapacity(.__wasm_init_memory, {});
285 const empty = try wasm.internValtypeList(&.{});
286 _ = try wasm.addFuncType(.{ .params = empty, .returns = empty });
285 }287 }
286288
287 // When we have TLS GOT entries and shared memory is enabled,289 // When we have TLS GOT entries and shared memory is enabled,
...@@ -711,9 +713,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -711,9 +713,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
711 }713 }
712714
713 // start section715 // start section
714 if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {716 if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| {
715 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);717 try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @enumFromInt(func_index)));
716 replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(func_index));718 } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| {
719 try emitStartSection(gpa, binary_bytes, func_index);
717 }720 }
718721
719 // element section722 // element section
...@@ -846,10 +849,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -846,10 +849,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
846 group_end_addr = f.data_segment_groups.items[group_index].end_addr;849 group_end_addr = f.data_segment_groups.items[group_index].end_addr;
847 segment_offset = 0;850 segment_offset = 0;
848 }851 }
849 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;
850 if (segment_offset == 0) {852 if (segment_offset == 0) {
851 const group_size = group_end_addr - group_start_addr;853 const group_size = group_end_addr - group_start_addr;
852 log.debug("emit data section group, {d} bytes", .{group_size});854 log.debug("emit data section group, {d} bytes", .{group_size});
855 const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active;
853 try leb.writeUleb128(binary_writer, @intFromEnum(flags));856 try leb.writeUleb128(binary_writer, @intFromEnum(flags));
854 // Passive segments are initialized at runtime.857 // Passive segments are initialized at runtime.
855 if (flags != .passive) {858 if (flags != .passive) {
...@@ -857,7 +860,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -857,7 +860,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
857 }860 }
858 try leb.writeUleb128(binary_writer, group_size);861 try leb.writeUleb128(binary_writer, group_size);
859 }862 }
860 if (flags == .passive or segment_id.isEmpty(wasm)) {863 if (segment_id.isEmpty(wasm)) {
861 // It counted for virtual memory but it does not go into the binary.864 // It counted for virtual memory but it does not go into the binary.
862 continue;865 continue;
863 }866 }
...@@ -1900,6 +1903,11 @@ fn emitInitMemoryFunction(...@@ -1900,6 +1903,11 @@ fn emitInitMemoryFunction(
1900 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1903 binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1901}1904}
19021905
1906fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void {
1907 const header_offset = try reserveVecSectionHeader(gpa, bytes);
1908 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));
1909}
1910
1903fn emitTagNameFunction(1911fn emitTagNameFunction(
1904 wasm: *Wasm,1912 wasm: *Wasm,
1905 code: *std.ArrayListUnmanaged(u8),1913 code: *std.ArrayListUnmanaged(u8),