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(...@@ -738,19 +738,32 @@ fn lowerNavRef(
738 dev.check(link.File.Tag.wasm.devFeature());738 dev.check(link.File.Tag.wasm.devFeature());
739 const wasm = lf.cast(.wasm).?;739 const wasm = lf.cast(.wasm).?;
740 assert(reloc_parent == .none);740 assert(reloc_parent == .none);
741 if (is_obj) {741 if (is_fn_body) {
742 try wasm.out_relocs.append(gpa, .{742 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
743 .offset = @intCast(code.items.len),743 if (!gop.found_existing) gop.value_ptr.* = {};
744 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },744 if (is_obj) {
745 .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64,745 @panic("TODO add out_reloc for this");
746 .addend = @intCast(offset),746 } else {
747 });747 try wasm.func_table_fixups.append(gpa, .{
748 .table_index = @enumFromInt(gop.index),
749 .offset = @intCast(code.items.len),
750 });
751 }
748 } else {752 } else {
749 try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1);753 if (is_obj) {
750 wasm.nav_fixups.appendAssumeCapacity(.{754 try wasm.out_relocs.append(gpa, .{
751 .navs_exe_index = try wasm.refNavExe(nav_index),755 .offset = @intCast(code.items.len),
752 .offset = @intCast(code.items.len),756 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) },
753 });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 }
754 }767 }
755 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);768 code.appendNTimesAssumeCapacity(0, ptr_width_bytes);
756 return;769 return;
src/link/Wasm.zig+14-3
...@@ -151,7 +151,11 @@ uav_fixups: std.ArrayListUnmanaged(UavFixup) = .empty,...@@ -151,7 +151,11 @@ uav_fixups: std.ArrayListUnmanaged(UavFixup) = .empty,
151/// List of locations within `string_bytes` that must be patched with the virtual151/// List of locations within `string_bytes` that must be patched with the virtual
152/// memory address of a Nav during `flush`.152/// memory address of a Nav during `flush`.
153/// When emitting an object file, `out_relocs` is used instead.153/// When emitting an object file, `out_relocs` is used instead.
154/// No functions here only global variables.
154nav_fixups: std.ArrayListUnmanaged(NavFixup) = .empty,155nav_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,
155/// Symbols to be emitted into an object file. Remains empty when not emitting159/// Symbols to be emitted into an object file. Remains empty when not emitting
156/// an object file.160/// an object file.
157symbol_table: std.AutoArrayHashMapUnmanaged(String, void) = .empty,161symbol_table: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
...@@ -307,6 +311,12 @@ pub const NavFixup = extern struct {...@@ -307,6 +311,12 @@ pub const NavFixup = extern struct {
307 offset: u32,311 offset: u32,
308};312};
309313
314pub const FuncTableFixup = extern struct {
315 table_index: ZcuIndirectFunctionSetIndex,
316 /// Index into `string_bytes`.
317 offset: u32,
318};
319
310/// Index into `objects`.320/// Index into `objects`.
311pub const ObjectIndex = enum(u32) {321pub const ObjectIndex = enum(u32) {
312 _,322 _,
...@@ -2208,7 +2218,7 @@ pub const FunctionImportId = enum(u32) {...@@ -2208,7 +2218,7 @@ pub const FunctionImportId = enum(u32) {
2208 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) FunctionImportId {2218 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) FunctionImportId {
2209 return switch (unpacked) {2219 return switch (unpacked) {
2210 .object_function_import => |i| @enumFromInt(@intFromEnum(i)),2220 .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),
2212 };2222 };
2213 }2223 }
22142224
...@@ -2295,7 +2305,7 @@ pub const GlobalImportId = enum(u32) {...@@ -2295,7 +2305,7 @@ pub const GlobalImportId = enum(u32) {
2295 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {2305 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) GlobalImportId {
2296 return switch (unpacked) {2306 return switch (unpacked) {
2297 .object_global_import => |i| @enumFromInt(@intFromEnum(i)),2307 .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),
2299 };2309 };
2300 }2310 }
23012311
...@@ -2360,7 +2370,7 @@ pub const DataImportId = enum(u32) {...@@ -2360,7 +2370,7 @@ pub const DataImportId = enum(u32) {
2360 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) DataImportId {2370 pub fn pack(unpacked: Unpacked, wasm: *const Wasm) DataImportId {
2361 return switch (unpacked) {2371 return switch (unpacked) {
2362 .object_data_import => |i| @enumFromInt(@intFromEnum(i)),2372 .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),
2364 };2374 };
2365 }2375 }
23662376
...@@ -3027,6 +3037,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -3027,6 +3037,7 @@ pub fn deinit(wasm: *Wasm) void {
3027 wasm.out_relocs.deinit(gpa);3037 wasm.out_relocs.deinit(gpa);
3028 wasm.uav_fixups.deinit(gpa);3038 wasm.uav_fixups.deinit(gpa);
3029 wasm.nav_fixups.deinit(gpa);3039 wasm.nav_fixups.deinit(gpa);
3040 wasm.func_table_fixups.deinit(gpa);
30303041
3031 wasm.zcu_indirect_function_set.deinit(gpa);3042 wasm.zcu_indirect_function_set.deinit(gpa);
3032 wasm.object_indirect_function_import_set.deinit(gpa);3043 wasm.object_indirect_function_import_set.deinit(gpa);
src/link/Wasm/Flush.zig+13
...@@ -54,6 +54,11 @@ const IndirectFunctionTableIndex = enum(u32) {...@@ -54,6 +54,11 @@ const IndirectFunctionTableIndex = enum(u32) {
54 fn fromOutputFunctionIndex(f: *const Flush, i: Wasm.OutputFunctionIndex) IndirectFunctionTableIndex {54 fn fromOutputFunctionIndex(f: *const Flush, i: Wasm.OutputFunctionIndex) IndirectFunctionTableIndex {
55 return @enumFromInt(f.indirect_function_table.getIndex(i).?);55 return @enumFromInt(f.indirect_function_table.getIndex(i).?);
56 }56 }
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 }
57};62};
5863
59const DataSegmentGroup = struct {64const DataSegmentGroup = struct {
...@@ -755,6 +760,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -755,6 +760,14 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
755 mem.writeInt(u64, wasm.string_bytes.items[nav_fixup.offset..][0..8], vaddr, .little);760 mem.writeInt(u64, wasm.string_bytes.items[nav_fixup.offset..][0..8], vaddr, .little);
756 }761 }
757 }762 }
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 }
758 }771 }
759772
760 // Data section.773 // Data section.