authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-10 00:42:04-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
loga327d238f1fa6c79ac8254785082b8ffb54945f0
treeda521e3f1e3cce70072f0bf6fc07eefa2d474d84
parentd999a8e33b75a6ddd477cc71d8f682fe703496eb

wasm linker: handle function data references properly


3 files changed, 52 insertions(+), 15 deletions(-)

src/codegen.zig+25-12
......@@ -738,19 +738,32 @@ fn lowerNavRef(
738738 dev.check(link.File.Tag.wasm.devFeature());
739739 const wasm = lf.cast(.wasm).?;
740740 assert(reloc_parent == .none);
741 if (is_obj) {
742 try wasm.out_relocs.append(gpa, .{
743 .offset = @intCast(code.items.len),
744 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
745 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
746 .addend = @intCast(offset),
747 });
741 if (is_fn_body) {
742 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
743 if (!gop.found_existing) gop.value_ptr.* = {};
744 if (is_obj) {
745 @panic("TODO add out_reloc for this");
746 } else {
747 try wasm.func_table_fixups.append(gpa, .{
748 .table_index = @enumFromInt(gop.index),
749 .offset = @intCast(code.items.len),
750 });
751 }
748752 } else {
749 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
750 wasm.nav_fixups.appendAssumeCapacity(.{
751 .navs_exe_index = try wasm.refNavExe(nav_index),
752 .offset = @intCast(code.items.len),
753 });
753 if (is_obj) {
754 try wasm.out_relocs.append(gpa, .{
755 .offset = @intCast(code.items.len),
756 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
757 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,
758 .addend = @intCast(offset),
759 });
760 } else {
761 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);
762 wasm.nav_fixups.appendAssumeCapacity(.{
763 .navs_exe_index = try wasm.refNavExe(nav_index),
764 .offset = @intCast(code.items.len),
765 });
766 }
754767 }
755768 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);
756769 return;
src/link/Wasm.zig+14-3
......@@ -151,7 +151,11 @@ uav_fixups: std.ArrayListUnmanaged(UavFixup) = .empty,
151151/// List of locations within `string_bytes` that must be patched with the virtual
152152/// memory address of a Nav during `flush`.
153153/// When emitting an object file, `out_relocs` is used instead.
154/// No functions here only global variables.
154155nav_fixups: std.ArrayListUnmanaged(NavFixup) = .empty,
156/// When a nav reference is a function pointer, this tracks the required function
157/// table entry index that needs to overwrite the code in the final output.
158func_table_fixups: std.ArrayListUnmanaged(FuncTableFixup) = .empty,
155159/// Symbols to be emitted into an object file. Remains empty when not emitting
156160/// an object file.
157161symbol_table: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
......@@ -307,6 +311,12 @@ pub const NavFixup = extern struct {
307311 offset: u32,
308312};
309313
314pub const FuncTableFixup = extern struct {
315 table_index: ZcuIndirectFunctionSetIndex,
316 /// Index into `string_bytes`.
317 offset: u32,
318};
319
310320/// Index into `objects`.
311321pub const ObjectIndex = enum(u32) {
312322 _,
......@@ -2208,7 +2218,7 @@ pub const FunctionImportId = enum(u32) {
22082218 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) FunctionImportId {
22092219 return switch (unpacked) {
22102220 .object_function_import => |i| @enumFromInt(@intFromEnum(i)),
2211 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_function_imports.entries.len),
2221 .zcu_import => |i| @enumFromInt(@intFromEnum(i) + wasm.object_function_imports.entries.len),
22122222 };
22132223 }
22142224
......@@ -2295,7 +2305,7 @@ pub const GlobalImportId = enum(u32) {
22952305 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
22962306 return switch (unpacked) {
22972307 .object_global_import => |i| @enumFromInt(@intFromEnum(i)),
2298 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_global_imports.entries.len),
2308 .zcu_import => |i| @enumFromInt(@intFromEnum(i) + wasm.object_global_imports.entries.len),
22992309 };
23002310 }
23012311
......@@ -2360,7 +2370,7 @@ pub const DataImportId = enum(u32) {
23602370 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) DataImportId {
23612371 return switch (unpacked) {
23622372 .object_data_import => |i| @enumFromInt(@intFromEnum(i)),
2363 .zcu_import => |i| @enumFromInt(@intFromEnum(i) - wasm.object_data_imports.entries.len),
2373 .zcu_import => |i| @enumFromInt(@intFromEnum(i) + wasm.object_data_imports.entries.len),
23642374 };
23652375 }
23662376
......@@ -3027,6 +3037,7 @@ pub fn deinit(wasm: *Wasm) void {
30273037 wasm.out_relocs.deinit(gpa);
30283038 wasm.uav_fixups.deinit(gpa);
30293039 wasm.nav_fixups.deinit(gpa);
3040 wasm.func_table_fixups.deinit(gpa);
30303041
30313042 wasm.zcu_indirect_function_set.deinit(gpa);
30323043 wasm.object_indirect_function_import_set.deinit(gpa);
src/link/Wasm/Flush.zig+13
......@@ -54,6 +54,11 @@ const IndirectFunctionTableIndex = enum(u32) {
5454 fn fromOutputFunctionIndex(f: *const Flush, i: Wasm.OutputFunctionIndex) IndirectFunctionTableIndex {
5555 return @enumFromInt(f.indirect_function_table.getIndex(i).?);
5656 }
57
58 fn fromZcuIndirectFunctionSetIndex(i: Wasm.ZcuIndirectFunctionSetIndex) IndirectFunctionTableIndex {
59 // These are the same since those are added to the table first.
60 return @enumFromInt(@intFromEnum(i));
61 }
5762};
5863
5964const DataSegmentGroup = struct {
......@@ -755,6 +760,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
755760 mem.writeInt(u64, wasm.string_bytes.items[nav_fixup.offset..][0..8], vaddr, .little);
756761 }
757762 }
763 for (wasm.func_table_fixups.items) |fixup| {
764 const table_index: IndirectFunctionTableIndex = .fromZcuIndirectFunctionSetIndex(fixup.table_index);
765 if (!is64) {
766 mem.writeInt(u32, wasm.string_bytes.items[fixup.offset..][0..4], @intFromEnum(table_index), .little);
767 } else {
768 mem.writeInt(u64, wasm.string_bytes.items[fixup.offset..][0..8], @intFromEnum(table_index), .little);
769 }
770 }
758771 }
759772
760773 // Data section.