authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-03-26 11:19:33+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-28 16:50:43+00:00
log6ed9c0521055add99097fd43598d5a8e1e3665ff
tree935152d9ce5fc23ad30dec62a397c9daba76fa9e
parent4a494a8cf94596e73a7ace576111500be7a6f758
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 35 insertions(+), 31 deletions(-)

src/link/Wasm/Object.zig+35-31
...@@ -969,6 +969,41 @@ pub fn parse(...@@ -969,6 +969,41 @@ pub fn parse(
969 func.type_index = func_type.ptr(ss).*;969 func.type_index = func_type.ptr(ss).*;
970 }970 }
971971
972 // Check for indirect function table in case of an MVP object file.
973 legacy_indirect_function_table: {
974 // If there is a symbol for each import table, this is not a legacy object file.
975 if (ss.table_imports.items.len == table_import_symbol_count) break :legacy_indirect_function_table;
976 if (table_import_symbol_count != 0) {
977 return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{
978 ss.table_imports.items.len, table_import_symbol_count,
979 });
980 }
981 // MVP object files cannot have any table definitions, only imports
982 // (for the indirect function table).
983 const tables = wasm.object_tables.items[tables_start..];
984 if (tables.len > 0) {
985 return diags.failParse(path, "table definition without representing table symbols", .{});
986 }
987 if (ss.table_imports.items.len != 1) {
988 return diags.failParse(path, "found more than one table import, but no representing table symbols", .{});
989 }
990 const table_import_name = ss.table_imports.items[0].name;
991 if (table_import_name != wasm.preloaded_strings.__indirect_function_table) {
992 return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
993 table_import_name.slice(wasm),
994 });
995 }
996
997 try ss.symbol_table.append(gpa, .{
998 .flags = .{
999 .undefined = true,
1000 .no_strip = true,
1001 },
1002 .name = table_import_name.toOptional(),
1003 .pointee = .{ .table_import = @enumFromInt(0) },
1004 });
1005 }
1006
972 // Apply symbol table information.1007 // Apply symbol table information.
973 for (ss.symbol_table.items) |symbol| switch (symbol.pointee) {1008 for (ss.symbol_table.items) |symbol| switch (symbol.pointee) {
974 .function_import => |index| {1009 .function_import => |index| {
...@@ -1331,37 +1366,6 @@ pub fn parse(...@@ -1331,37 +1366,6 @@ pub fn parse(
1331 };1366 };
1332 }1367 }
13331368
1334 // Check for indirect function table in case of an MVP object file.
1335 legacy_indirect_function_table: {
1336 // If there is a symbol for each import table, this is not a legacy object file.
1337 if (ss.table_imports.items.len == table_import_symbol_count) break :legacy_indirect_function_table;
1338 if (table_import_symbol_count != 0) {
1339 return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{
1340 ss.table_imports.items.len, table_import_symbol_count,
1341 });
1342 }
1343 // MVP object files cannot have any table definitions, only imports
1344 // (for the indirect function table).
1345 const tables = wasm.object_tables.items[tables_start..];
1346 if (tables.len > 0) {
1347 return diags.failParse(path, "table definition without representing table symbols", .{});
1348 }
1349 if (ss.table_imports.items.len != 1) {
1350 return diags.failParse(path, "found more than one table import, but no representing table symbols", .{});
1351 }
1352 const table_import_name = ss.table_imports.items[0].name;
1353 if (table_import_name != wasm.preloaded_strings.__indirect_function_table) {
1354 return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
1355 table_import_name.slice(wasm),
1356 });
1357 }
1358 const ptr = wasm.object_table_imports.getPtr(table_import_name).?;
1359 ptr.flags = .{
1360 .undefined = true,
1361 .no_strip = true,
1362 };
1363 }
1364
1365 for (wasm.object_init_funcs.items[init_funcs_start..]) |init_func| {1369 for (wasm.object_init_funcs.items[init_funcs_start..]) |init_func| {
1366 const func = init_func.function_index.ptr(wasm);1370 const func = init_func.function_index.ptr(wasm);
1367 const params = func.type_index.ptr(wasm).params.slice(wasm);1371 const params = func.type_index.ptr(wasm).params.slice(wasm);