authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-14 19:31:45+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-03-18 20:13:29+01:00
log00af3a79aede098c60eeff38ad72fa399b9d3ccf
tree17badac16ab8b35d7f1c6217a4aaf7cadd672ba5
parentfb9d3cd50e9a6d112277d7de158ef857162c01d9
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: emit 'data count' & segment flags

When linking with shared-memory enabled, we must ensure to emit the "data count" section as well as emit the correct segment flags to tell the runtime/loader that each segment is passive. This is required as we don't emit the offsets for such segments but instead initialize each segment (for each thread) during runtime.

1 files changed, 49 insertions(+), 5 deletions(-)

src/link/Wasm.zig+49-5
......@@ -180,6 +180,16 @@ pub const Segment = struct {
180180 alignment: u32,
181181 size: u32,
182182 offset: u32,
183 flags: u32,
184
185 pub const Flag = enum(u32) {
186 WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,
187 WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
188 };
189
190 pub fn isPassive(segment: Segment) bool {
191 return segment.flags & @enumToInt(Flag.WASM_DATA_SEGMENT_IS_PASSIVE) != 0;
192 }
183193};
184194
185195pub const Export = struct {
......@@ -1673,6 +1683,7 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
16731683 .alignment = atom.alignment,
16741684 .size = atom.size,
16751685 .offset = 0,
1686 .flags = 0,
16761687 });
16771688 }
16781689
......@@ -1711,10 +1722,15 @@ fn parseAtom(wasm: *Wasm, atom_index: Atom.Index, kind: Kind) !void {
17111722 break :result index;
17121723 } else {
17131724 const index = @intCast(u32, wasm.segments.items.len);
1725 var flags: u32 = 0;
1726 if (wasm.base.options.shared_memory) {
1727 flags |= @enumToInt(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
1728 }
17141729 try wasm.segments.append(wasm.base.allocator, .{
17151730 .alignment = atom.alignment,
17161731 .size = 0,
17171732 .offset = 0,
1733 .flags = flags,
17181734 });
17191735 gop.value_ptr.* = index;
17201736
......@@ -2365,7 +2381,16 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
23652381 const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
23662382 if (!result.found_existing) {
23672383 result.value_ptr.* = index;
2368 try wasm.appendDummySegment();
2384 var flags: u32 = 0;
2385 if (wasm.base.options.shared_memory) {
2386 flags |= @enumToInt(Segment.Flag.WASM_DATA_SEGMENT_IS_PASSIVE);
2387 }
2388 try wasm.segments.append(wasm.base.allocator, .{
2389 .alignment = 1,
2390 .size = 0,
2391 .offset = 0,
2392 .flags = flags,
2393 });
23692394 return index;
23702395 } else return result.value_ptr.*;
23712396 },
......@@ -2439,6 +2464,7 @@ fn appendDummySegment(wasm: *Wasm) !void {
24392464 .alignment = 1,
24402465 .size = 0,
24412466 .offset = 0,
2467 .flags = 0,
24422468 });
24432469}
24442470
......@@ -3147,6 +3173,19 @@ fn writeToFile(
31473173 section_count += 1;
31483174 }
31493175
3176 // When the shared-memory option is enabled, we *must* emit the 'data count' section.
3177 const data_segments_count = wasm.data_segments.count() - @boolToInt(wasm.data_segments.contains(".bss") and import_memory);
3178 if (data_segments_count != 0 and wasm.base.options.shared_memory) {
3179 const header_offset = try reserveVecSectionHeader(&binary_bytes);
3180 try writeVecSectionHeader(
3181 binary_bytes.items,
3182 header_offset,
3183 .data_count,
3184 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
3185 @intCast(u32, data_segments_count),
3186 );
3187 }
3188
31503189 // Code section
31513190 var code_section_size: u32 = 0;
31523191 if (wasm.code_section_index) |code_index| {
......@@ -3197,7 +3236,7 @@ fn writeToFile(
31973236 }
31983237
31993238 // Data section
3200 if (wasm.data_segments.count() != 0) {
3239 if (data_segments_count != 0) {
32013240 const header_offset = try reserveVecSectionHeader(&binary_bytes);
32023241
32033242 var it = wasm.data_segments.iterator();
......@@ -3212,10 +3251,15 @@ fn writeToFile(
32123251 segment_count += 1;
32133252 var atom_index = wasm.atoms.get(segment_index).?;
32143253
3215 // flag and index to memory section (currently, there can only be 1 memory section in wasm)
3216 try leb.writeULEB128(binary_writer, @as(u32, 0));
3254 try leb.writeULEB128(binary_writer, segment.flags);
3255 if (segment.flags & @enumToInt(Wasm.Segment.Flag.WASM_DATA_SEGMENT_HAS_MEMINDEX) != 0) {
3256 try leb.writeULEB128(binary_writer, @as(u32, 0)); // memory is always index 0 as we only have 1 memory entry
3257 }
3258 // when a segment is passive, it's initialized during runtime.
3259 if (!segment.isPassive()) {
3260 try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) });
3261 }
32173262 // offset into data section
3218 try emitInit(binary_writer, .{ .i32_const = @bitCast(i32, segment.offset) });
32193263 try leb.writeULEB128(binary_writer, segment.size);
32203264
32213265 // fill in the offset table and the data segments