diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-12-11 22:18:53 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-01-15 15:11:35 -0800 |
| commit | bf880595916cad2a21fca2834e334c2b0ac09f24 (patch) | |
| tree | 223e2737f73973ab4a4ed5395963c252e507245a /src | |
| parent | e21a42723b9acefd27c142bf776a8321621296b8 (diff) | |
| download | zig-bf880595916cad2a21fca2834e334c2b0ac09f24.tar.gz zig-bf880595916cad2a21fca2834e334c2b0ac09f24.zip | |
wasm linker: flush implemented up to the export section
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Wasm.zig | 241 | ||||
| -rw-r--r-- | src/link/Wasm/Flush.zig | 263 | ||||
| -rw-r--r-- | src/link/Wasm/Object.zig | 8 |
3 files changed, 320 insertions, 192 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index e6fb60d9ec..f27ad9109f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -404,7 +404,7 @@ pub const SymbolFlags = packed struct(u32) { /// Zig-specific. Data segments only. alignment: Alignment = .none, /// Zig-specific. Globals only. - global_type: Global.Type = .zero, + global_type: GlobalType4 = .zero, /// Zig-specific. Tables only. limits_has_max: bool = false, /// Zig-specific. Tables only. @@ -481,6 +481,48 @@ pub const SymbolFlags = packed struct(u32) { } }; +pub const GlobalType4 = packed struct(u4) { + valtype: Valtype3, + mutable: bool, + + pub const zero: GlobalType4 = @bitCast(@as(u4, 0)); + + pub fn to(gt: GlobalType4) Global.Type { + return .{ + .valtype = gt.valtype.to(), + .mutable = gt.mutable, + }; + } +}; + +pub const Valtype3 = enum(u3) { + i32, + i64, + f32, + f64, + v128, + + pub fn from(v: std.wasm.Valtype) Valtype3 { + return switch (v) { + .i32 => .i32, + .i64 => .i64, + .f32 => .f32, + .f64 => .f64, + .v128 => .v128, + }; + } + + pub fn to(v: Valtype3) std.wasm.Valtype { + return switch (v) { + .i32 => .i32, + .i64 => .i64, + .f32 => .f32, + .f64 => .f64, + .v128 => .v128, + }; + } +}; + pub const NavObj = extern struct { code: DataSegment.Payload, /// Empty if not emitting an object. @@ -591,7 +633,7 @@ pub const FunctionImport = extern struct { __zig_error_names, object_function: ObjectFunctionIndex, nav_exe: NavExe.Index, - nav_obj: NavExe.Index, + nav_obj: NavObj.Index, }; pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked { @@ -649,6 +691,20 @@ pub const FunctionImport = extern struct { else => false, }; } + + pub fn typeIndex(r: Resolution, wasm: *const Wasm) FunctionType.Index { + return switch (unpack(r, wasm)) { + .unresolved => unreachable, + .__wasm_apply_global_tls_relocs => @panic("TODO"), + .__wasm_call_ctors => @panic("TODO"), + .__wasm_init_memory => @panic("TODO"), + .__wasm_init_tls => @panic("TODO"), + .__zig_error_names => @panic("TODO"), + .object_function => |i| i.ptr(wasm).type_index, + .nav_exe => @panic("TODO"), + .nav_obj => @panic("TODO"), + }; + } }; /// Index into `object_function_imports`. @@ -731,11 +787,13 @@ pub const GlobalImport = extern struct { pub fn unpack(r: Resolution, wasm: *const Wasm) Unpacked { return switch (r) { .unresolved => .unresolved, - .__wasm_apply_global_tls_relocs => .__wasm_apply_global_tls_relocs, - .__wasm_call_ctors => .__wasm_call_ctors, - .__wasm_init_memory => .__wasm_init_memory, - .__wasm_init_tls => .__wasm_init_tls, - .__zig_error_names => .__zig_error_names, + .__heap_base => .__heap_base, + .__heap_end => .__heap_end, + .__stack_pointer => .__stack_pointer, + .__tls_align => .__tls_align, + .__tls_base => .__tls_base, + .__tls_size => .__tls_size, + .__zig_error_name_table => .__zig_error_name_table, _ => { const i: u32 = @intFromEnum(r); const object_global_index = i - first_object_global; @@ -780,12 +838,28 @@ pub const GlobalImport = extern struct { } }; - /// Index into `object_global_imports`. + /// Index into `Wasm.object_global_imports`. pub const Index = enum(u32) { _, - pub fn ptr(index: Index, wasm: *const Wasm) *GlobalImport { - return &wasm.object_global_imports.items[@intFromEnum(index)]; + pub fn key(index: Index, wasm: *const Wasm) *String { + return &wasm.object_global_imports.keys()[@intFromEnum(index)]; + } + + pub fn value(index: Index, wasm: *const Wasm) *GlobalImport { + return &wasm.object_global_imports.values()[@intFromEnum(index)]; + } + + pub fn name(index: Index, wasm: *const Wasm) String { + return index.key(wasm).*; + } + + pub fn moduleName(index: Index, wasm: *const Wasm) String { + return index.value(wasm).module_name; + } + + pub fn globalType(index: Index, wasm: *const Wasm) Global.Type { + return value(index, wasm).flags.global_type.to(); } }; }; @@ -796,39 +870,9 @@ pub const Global = extern struct { flags: SymbolFlags, expr: Expr, - pub const Type = packed struct(u4) { - valtype: Valtype, + pub const Type = struct { + valtype: std.wasm.Valtype, mutable: bool, - - pub const zero: Type = @bitCast(@as(u4, 0)); - }; - - pub const Valtype = enum(u3) { - i32, - i64, - f32, - f64, - v128, - - pub fn from(v: std.wasm.Valtype) Valtype { - return switch (v) { - .i32 => .i32, - .i64 => .i64, - .f32 => .f32, - .f64 => .f64, - .v128 => .v128, - }; - } - - pub fn to(v: Valtype) std.wasm.Valtype { - return switch (v) { - .i32 => .i32, - .i64 => .i64, - .f32 => .f32, - .f64 => .f64, - .v128 => .v128, - }; - } }; }; @@ -865,6 +909,38 @@ pub const TableImport = extern struct { __indirect_function_table, // Next, index into `object_tables`. _, + + const first_object_table = @intFromEnum(Resolution.__indirect_function_table) + 1; + + pub const Unpacked = union(enum) { + unresolved, + __indirect_function_table, + object_table: ObjectTableIndex, + }; + + pub fn unpack(r: Resolution) Unpacked { + return switch (r) { + .unresolved => .unresolved, + .__indirect_function_table => .__indirect_function_table, + _ => .{ .object_table = @enumFromInt(@intFromEnum(r) - first_object_table) }, + }; + } + + pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType { + return switch (unpack(r)) { + .unresolved => unreachable, + .__indirect_function_table => @panic("TODO"), + .object_table => |i| i.ptr(wasm).flags.ref_type.to(), + }; + } + + pub fn limits(r: Resolution, wasm: *const Wasm) std.wasm.Limits { + return switch (unpack(r)) { + .unresolved => unreachable, + .__indirect_function_table => @panic("TODO"), + .object_table => |i| i.ptr(wasm).limits(), + }; + } }; /// Index into `object_table_imports`. @@ -878,7 +954,26 @@ pub const TableImport = extern struct { pub fn value(index: Index, wasm: *const Wasm) *TableImport { return &wasm.object_table_imports.values()[@intFromEnum(index)]; } + + pub fn name(index: Index, wasm: *const Wasm) String { + return index.key(wasm).*; + } + + pub fn moduleName(index: Index, wasm: *const Wasm) String { + return index.value(wasm).module_name; + } }; + + pub fn limits(ti: *const TableImport) std.wasm.Limits { + return .{ + .flags = .{ + .has_max = ti.flags.limits_has_max, + .is_shared = ti.flags.limits_is_shared, + }, + .min = ti.limits_min, + .max = ti.limits_max, + }; + } }; pub const Table = extern struct { @@ -887,6 +982,17 @@ pub const Table = extern struct { flags: SymbolFlags, limits_min: u32, limits_max: u32, + + pub fn limits(t: *const Table) std.wasm.Limits { + return .{ + .flags = .{ + .has_max = t.flags.limits_has_max, + .is_shared = t.flags.limits_is_shared, + }, + .min = t.limits_min, + .max = t.limits_max, + }; + } }; /// Uniquely identifies a section across all objects. By subtracting @@ -910,9 +1016,13 @@ pub const GlobalImportIndex = enum(u32) { _, }; -/// Index into `object_globals`. +/// Index into `Wasm.object_globals`. pub const ObjectGlobalIndex = enum(u32) { _, + + pub fn ptr(index: ObjectGlobalIndex, wasm: *const Wasm) *Global { + return &wasm.object_globals.items[@intFromEnum(index)]; + } }; /// Index into `Wasm.object_memories`. @@ -992,6 +1102,16 @@ pub const CustomSegment = extern struct { /// An index into string_bytes where a wasm expression is found. pub const Expr = enum(u32) { _, + + pub const end = @intFromEnum(std.wasm.Opcode.end); + + pub fn slice(index: Expr, wasm: *const Wasm) [:end]const u8 { + const start_slice = wasm.string_bytes.items[@intFromEnum(index)..]; + const end_pos = Object.exprEndPos(start_slice, 0) catch |err| switch (err) { + error.InvalidInitOpcode => unreachable, + }; + return start_slice[0..end_pos :end]; + } }; pub const FunctionType = extern struct { @@ -1162,6 +1282,12 @@ pub const ZcuImportIndex = enum(u32) { const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?; return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?; } + + pub fn globalType(index: ZcuImportIndex, wasm: *const Wasm) Global.Type { + _ = index; + _ = wasm; + unreachable; // Zig has no way to create Wasm globals yet. + } }; /// 0. Index into `object_function_imports`. @@ -1274,6 +1400,24 @@ pub const GlobalImportId = enum(u32) { .zcu_import => return .zig_object_nofile, // TODO give a better source location } } + + pub fn name(id: GlobalImportId, wasm: *const Wasm) String { + return switch (unpack(id, wasm)) { + inline .object_global_import, .zcu_import => |i| i.name(wasm), + }; + } + + pub fn moduleName(id: GlobalImportId, wasm: *const Wasm) String { + return switch (unpack(id, wasm)) { + inline .object_global_import, .zcu_import => |i| i.moduleName(wasm), + }; + } + + pub fn globalType(id: GlobalImportId, wasm: *Wasm) Global.Type { + return switch (unpack(id, wasm)) { + inline .object_global_import, .zcu_import => |i| i.globalType(wasm), + }; + } }; /// Index into `Wasm.symbol_table`. @@ -1384,6 +1528,17 @@ pub const MemoryImport = extern struct { limits_has_max: bool, limits_is_shared: bool, padding: [2]u8 = .{ 0, 0 }, + + pub fn limits(mi: *const MemoryImport) std.wasm.Limits { + return .{ + .flags = .{ + .has_max = mi.limits_has_max, + .is_shared = mi.limits_is_shared, + }, + .min = mi.limits_min, + .max = mi.limits_max, + }; + } }; pub const Alignment = InternPool.Alignment; diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 35b6ee74bb..ed48f39e48 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -335,8 +335,6 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { log.debug("maximum memory pages: {?d}", .{wasm.memories.limits.max}); } - // Size of each section header - const header_size = 5 + 1; var section_index: u32 = 0; // Index of the code section. Used to tell relocation table where the section lives. var code_section_index: ?u32 = null; @@ -369,54 +367,50 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { } } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .type, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.func_types.entries.len), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(wasm.func_types.entries.len)); section_index += 1; } // Import section - const total_imports_len = wasm.function_imports.entries.len + wasm.global_imports.entries.len + - wasm.table_imports.entries.len + wasm.object_memory_imports.items.len + @intFromBool(import_memory); - - if (total_imports_len > 0) { + { + var total_imports: usize = 0; const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - for (wasm.function_imports.values()) |*function_import| { - const module_name = function_import.moduleName(wasm).slice(wasm); + for (wasm.function_imports.values()) |id| { + const module_name = id.moduleName(wasm).slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); try binary_writer.writeAll(module_name); - const name = function_import.name(wasm).slice(wasm); + const name = id.name(wasm).slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); try binary_writer.writeAll(name); try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); - try leb.writeUleb128(binary_writer, @intFromEnum(function_import.functionType(wasm))); + try leb.writeUleb128(binary_writer, @intFromEnum(id.functionType(wasm))); } + total_imports += wasm.function_imports.entries.len; - for (wasm.table_imports.values()) |*table_import| { - const module_name = table_import.moduleName(wasm).slice(wasm); + for (wasm.table_imports.values()) |id| { + const table_import = id.value(wasm); + const module_name = table_import.module_name.slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); try binary_writer.writeAll(module_name); - const name = table_import.name(wasm).slice(wasm); + const name = id.key(wasm).slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); try binary_writer.writeAll(name); try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); - try leb.writeUleb128(binary_writer, std.wasm.reftype(table_import.reftype)); - try emitLimits(binary_writer, table_import.limits); + try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); + try emitLimits(gpa, binary_bytes, table_import.limits()); } + total_imports += wasm.table_imports.entries.len; for (wasm.object_memory_imports.items) |*memory_import| { - try emitMemoryImport(wasm, binary_writer, memory_import); + try emitMemoryImport(wasm, binary_bytes, memory_import); + total_imports += 1; } else if (import_memory) { - try emitMemoryImport(wasm, binary_writer, &.{ + try emitMemoryImport(wasm, binary_bytes, &.{ .module_name = wasm.host_name, .name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory, .limits_min = wasm.memories.limits.min, @@ -424,100 +418,87 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { .limits_has_max = wasm.memories.limits.flags.has_max, .limits_is_shared = wasm.memories.limits.flags.is_shared, }); + total_imports += 1; } - for (wasm.global_imports.values()) |*global_import| { - const module_name = global_import.module_name.slice(wasm); + for (wasm.global_imports.values()) |id| { + const module_name = id.moduleName(wasm).slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); try binary_writer.writeAll(module_name); - const name = global_import.name.slice(wasm); + const name = id.name(wasm).slice(wasm); try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); try binary_writer.writeAll(name); try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); - try leb.writeUleb128(binary_writer, @intFromEnum(global_import.valtype)); - try binary_writer.writeByte(@intFromBool(global_import.mutable)); + const global_type = id.globalType(wasm); + try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype))); + try binary_writer.writeByte(@intFromBool(global_type.mutable)); } + total_imports += wasm.global_imports.entries.len; - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .import, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(total_imports_len), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports)); section_index += 1; } // Function section if (wasm.functions.count() != 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - for (wasm.functions.values()) |function| { - try leb.writeUleb128(binary_writer, function.func.type_index); + for (wasm.functions.keys()) |function| { + try leb.writeUleb128(binary_writer, @intFromEnum(function.typeIndex(wasm))); } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .function, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.functions.count()), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count())); section_index += 1; } // Table section - if (wasm.tables.items.len > 0) { + if (wasm.tables.entries.len > 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - for (wasm.tables.items) |table| { - try leb.writeUleb128(binary_writer, std.wasm.reftype(table.reftype)); - try emitLimits(binary_writer, table.limits); + for (wasm.tables.keys()) |table| { + try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm)))); + try emitLimits(gpa, binary_bytes, table.limits(wasm)); } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .table, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.tables.items.len), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .table, @intCast(wasm.tables.entries.len)); section_index += 1; } - // Memory section + // Memory section. wasm currently only supports 1 linear memory segment. if (!import_memory) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - - try emitLimits(binary_writer, wasm.memories.limits); - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .memory, - @intCast(binary_bytes.items.len - header_offset - header_size), - 1, // wasm currently only supports 1 linear memory segment - ); + try emitLimits(gpa, binary_bytes, wasm.memories.limits); + replaceVecSectionHeader(binary_bytes, header_offset, .memory, 1); section_index += 1; } // Global section (used to emit stack pointer) - if (wasm.output_globals.items.len > 0) { + if (wasm.globals.entries.len > 0) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - for (wasm.output_globals.items) |global| { - try binary_writer.writeByte(@intFromEnum(global.global_type.valtype)); - try binary_writer.writeByte(@intFromBool(global.global_type.mutable)); - try emitInit(binary_writer, global.init); + for (wasm.globals.keys()) |global_resolution| { + switch (global_resolution.unpack(wasm)) { + .unresolved => unreachable, + .__heap_base => @panic("TODO"), + .__heap_end => @panic("TODO"), + .__stack_pointer => @panic("TODO"), + .__tls_align => @panic("TODO"), + .__tls_base => @panic("TODO"), + .__tls_size => @panic("TODO"), + .__zig_error_name_table => @panic("TODO"), + .object_global => |i| { + const global = i.ptr(wasm); + try binary_writer.writeByte(@intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to()))); + try binary_writer.writeByte(@intFromBool(global.flags.global_type.mutable)); + try emitExpr(wasm, binary_bytes, global.expr); + }, + .nav_exe => @panic("TODO"), + .nav_obj => @panic("TODO"), + } } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .global, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.output_globals.items.len), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .global, @intCast(wasm.globals.entries.len)); section_index += 1; } @@ -540,25 +521,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { try leb.writeUleb128(binary_writer, @as(u32, 0)); } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .@"export", - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.exports.items.len + @intFromBool(export_memory)), - ); + const n_items: u32 = @intCast(wasm.exports.items.len + @intFromBool(export_memory)); + replaceVecSectionHeader(binary_bytes, header_offset, .@"export", n_items); section_index += 1; } - if (wasm.entry) |entry_index| { + if (Wasm.FunctionIndex.fromResolution(wasm.entry_resolution)) |entry_index| { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .start, - @intCast(binary_bytes.items.len - header_offset - header_size), - entry_index, - ); + replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(entry_index)); } // element section (function table) @@ -586,26 +556,14 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { try leb.writeUleb128(binary_writer, sym.index); } - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .element, - @intCast(binary_bytes.items.len - header_offset - header_size), - 1, - ); + replaceVecSectionHeader(binary_bytes, header_offset, .element, 1); section_index += 1; } // When the shared-memory option is enabled, we *must* emit the 'data count' section. if (f.data_segment_groups.items.len > 0 and shared_memory) { const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .data_count, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(f.data_segment_groups.items.len), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); } // Code section. @@ -636,13 +594,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { }, }; - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .code, - @intCast(binary_bytes.items.len - header_offset - header_size), - @intCast(wasm.functions.count()), - ); + replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len)); code_section_index = section_index; section_index += 1; } @@ -682,13 +634,7 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void { } assert(group_index == f.data_segment_groups.items.len); - try writeVecSectionHeader( - binary_bytes.items, - header_offset, - .data, - @intCast(binary_bytes.items.len - header_offset - header_size), - group_index, - ); + replaceVecSectionHeader(binary_bytes, header_offset, .data, group_index); data_section_index = section_index; section_index += 1; } @@ -768,7 +714,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), arena }; var globals: std.MultiArrayList(NamedIndex) = .empty; - try globals.ensureTotalCapacityPrecise(arena, wasm.output_globals.items.len + wasm.global_imports.items.len); + try globals.ensureTotalCapacityPrecise(arena, wasm.globals.items.len + wasm.global_imports.items.len); var segments: std.MultiArrayList(NamedIndex) = .empty; try segments.ensureTotalCapacityPrecise(arena, wasm.data_segments.count()); @@ -844,10 +790,8 @@ fn writeCustomSectionHeader(buffer: []u8, offset: u32, size: u32) !void { } fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { - // unlike regular section, we don't emit the count - const header_size = 1 + 5; - try bytes.appendNTimes(gpa, 0, header_size); - return @intCast(bytes.items.len - header_size); + try bytes.appendNTimes(gpa, 0, section_header_size); + return @intCast(bytes.items.len - section_header_size); } fn emitNameSubsection( @@ -1106,38 +1050,57 @@ fn wantSegmentMerge(wasm: *const Wasm, a_index: Wasm.DataSegment.Index, b_index: return a_prefix.len > 0 and mem.eql(u8, a_prefix, b_prefix); } +/// section id + fixed leb contents size + fixed leb vector length +const section_header_reserve_size = 1 + 5 + 5; +const section_header_size = 5 + 1; + fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { - // section id + fixed leb contents size + fixed leb vector length - const header_size = 1 + 5 + 5; - try bytes.appendNTimes(gpa, 0, header_size); - return @intCast(bytes.items.len - header_size); + try bytes.appendNTimes(gpa, 0, section_header_reserve_size); + return @intCast(bytes.items.len - section_header_reserve_size); } -fn writeVecSectionHeader(buffer: []u8, offset: u32, section: std.wasm.Section, size: u32, items: u32) !void { - var buf: [1 + 5 + 5]u8 = undefined; - buf[0] = @intFromEnum(section); - leb.writeUnsignedFixed(5, buf[1..6], size); - leb.writeUnsignedFixed(5, buf[6..], items); - buffer[offset..][0..buf.len].* = buf; +fn replaceVecSectionHeader( + bytes: *std.ArrayListUnmanaged(u8), + offset: u32, + section: std.wasm.Section, + n_items: u32, +) void { + const size: u32 = @intCast(bytes.items.len - offset - section_header_size); + var buf: [section_header_reserve_size]u8 = undefined; + var fbw = std.io.fixedBufferStream(&buf); + const w = fbw.writer(); + w.writeByte(@intFromEnum(section)) catch unreachable; + leb.writeUleb128(w, size) catch unreachable; + leb.writeUleb128(w, n_items) catch unreachable; + bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten()); } -fn emitLimits(writer: anytype, limits: std.wasm.Limits) !void { - try writer.writeByte(limits.flags); - try leb.writeUleb128(writer, limits.min); - if (limits.flags.has_max) try leb.writeUleb128(writer, limits.max); +fn emitLimits( + gpa: Allocator, + binary_bytes: *std.ArrayListUnmanaged(u8), + limits: std.wasm.Limits, +) Allocator.Error!void { + try binary_bytes.append(gpa, @bitCast(limits.flags)); + try leb.writeUleb128(binary_bytes.writer(gpa), limits.min); + if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max); } -fn emitMemoryImport(wasm: *Wasm, writer: anytype, memory_import: *const Wasm.MemoryImport) Allocator.Error!void { +fn emitMemoryImport( + wasm: *Wasm, + binary_bytes: *std.ArrayListUnmanaged(u8), + memory_import: *const Wasm.MemoryImport, +) Allocator.Error!void { + const gpa = wasm.base.comp.gpa; const module_name = memory_import.module_name.slice(wasm); - try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len))); - try writer.writeAll(module_name); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len))); + try binary_bytes.appendSlice(gpa, module_name); const name = memory_import.name.slice(wasm); - try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); - try writer.writeAll(name); + try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); + try binary_bytes.appendSlice(gpa, name); - try writer.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); - try emitLimits(writer, memory_import.limits()); + try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory)); + try emitLimits(gpa, binary_bytes, memory_import.limits()); } pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { @@ -1166,6 +1129,12 @@ pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { try writer.writeByte(@intFromEnum(std.wasm.Opcode.end)); } +pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void { + const gpa = wasm.base.comp.gpa; + const slice = expr.slice(wasm); + try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode +} + //fn emitLinkSection( // wasm: *Wasm, // binary_bytes: *std.ArrayListUnmanaged(u8), diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index d46bef6371..c87260b2e0 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -1040,9 +1040,9 @@ fn readInit(wasm: *Wasm, bytes: []const u8, pos: usize) !struct { Wasm.Expr, usi return .{ try wasm.addExpr(bytes[pos..end_pos]), end_pos }; } -fn skipInit(bytes: []const u8, pos: usize) !usize { +pub fn exprEndPos(bytes: []const u8, pos: usize) error{InvalidInitOpcode}!usize { const opcode = bytes[pos]; - const end_pos = switch (@as(std.wasm.Opcode, @enumFromInt(opcode))) { + return switch (@as(std.wasm.Opcode, @enumFromInt(opcode))) { .i32_const => readLeb(i32, bytes, pos + 1)[1], .i64_const => readLeb(i64, bytes, pos + 1)[1], .f32_const => pos + 5, @@ -1050,6 +1050,10 @@ fn skipInit(bytes: []const u8, pos: usize) !usize { .global_get => readLeb(u32, bytes, pos + 1)[1], else => return error.InvalidInitOpcode, }; +} + +fn skipInit(bytes: []const u8, pos: usize) !usize { + const end_pos = try exprEndPos(bytes, pos); const op, const final_pos = readEnum(std.wasm.Opcode, bytes, end_pos); if (op != .end) return error.InitExprMissingEnd; return final_pos; |
