zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 6ed9c0521055add99097fd43598d5a8e1e3665ff (tree)
parent 4a494a8cf94596e73a7ace576111500be7a6f758
Author: Pavel Verigo <paul.verigo@gmail.com>
Date:   Thu, 26 Mar 2026 11:19:33 +0000

link.Wasm: fix indirect function table handling

The changes to the LLVM backend here changed the compiler_rt object
which LLVM emits, and exposed some buggy behavior in the self-hosted
WASM linker when parsing that object.

Diffstat:
Msrc/link/Wasm/Object.zig | 66+++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 35 insertions(+), 31 deletions(-)

diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig @@ -969,6 +969,41 @@ pub fn parse( func.type_index = func_type.ptr(ss).*; } + // Check for indirect function table in case of an MVP object file. + legacy_indirect_function_table: { + // If there is a symbol for each import table, this is not a legacy object file. + if (ss.table_imports.items.len == table_import_symbol_count) break :legacy_indirect_function_table; + if (table_import_symbol_count != 0) { + return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{ + ss.table_imports.items.len, table_import_symbol_count, + }); + } + // MVP object files cannot have any table definitions, only imports + // (for the indirect function table). + const tables = wasm.object_tables.items[tables_start..]; + if (tables.len > 0) { + return diags.failParse(path, "table definition without representing table symbols", .{}); + } + if (ss.table_imports.items.len != 1) { + return diags.failParse(path, "found more than one table import, but no representing table symbols", .{}); + } + const table_import_name = ss.table_imports.items[0].name; + if (table_import_name != wasm.preloaded_strings.__indirect_function_table) { + return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{ + table_import_name.slice(wasm), + }); + } + + try ss.symbol_table.append(gpa, .{ + .flags = .{ + .undefined = true, + .no_strip = true, + }, + .name = table_import_name.toOptional(), + .pointee = .{ .table_import = @enumFromInt(0) }, + }); + } + // Apply symbol table information. for (ss.symbol_table.items) |symbol| switch (symbol.pointee) { .function_import => |index| { @@ -1331,37 +1366,6 @@ pub fn parse( }; } - // Check for indirect function table in case of an MVP object file. - legacy_indirect_function_table: { - // If there is a symbol for each import table, this is not a legacy object file. - if (ss.table_imports.items.len == table_import_symbol_count) break :legacy_indirect_function_table; - if (table_import_symbol_count != 0) { - return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{ - ss.table_imports.items.len, table_import_symbol_count, - }); - } - // MVP object files cannot have any table definitions, only imports - // (for the indirect function table). - const tables = wasm.object_tables.items[tables_start..]; - if (tables.len > 0) { - return diags.failParse(path, "table definition without representing table symbols", .{}); - } - if (ss.table_imports.items.len != 1) { - return diags.failParse(path, "found more than one table import, but no representing table symbols", .{}); - } - const table_import_name = ss.table_imports.items[0].name; - if (table_import_name != wasm.preloaded_strings.__indirect_function_table) { - return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{ - table_import_name.slice(wasm), - }); - } - const ptr = wasm.object_table_imports.getPtr(table_import_name).?; - ptr.flags = .{ - .undefined = true, - .no_strip = true, - }; - } - for (wasm.object_init_funcs.items[init_funcs_start..]) |init_func| { const func = init_func.function_index.ptr(wasm); const params = func.type_index.ptr(wasm).params.slice(wasm);