| ... | @@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, | ... | @@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 112 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{}, | 112 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{}, |
| 113 | /// Output global section | 113 | /// Output global section |
| 114 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, | 114 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, |
| 115 | /// Global symbols for exported data symbols | | |
| 116 | address_globals: std.ArrayListUnmanaged(SymbolLoc) = .{}, | | |
| 117 | /// Memory section | 115 | /// Memory section |
| 118 | memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, | 116 | memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, |
| 119 | /// Output table section | 117 | /// Output table section |
| ... | @@ -335,41 +333,64 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -335,41 +333,64 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 335 | wasm_bin.base.file = file; | 333 | wasm_bin.base.file = file; |
| 336 | wasm_bin.name = sub_path; | 334 | wasm_bin.name = sub_path; |
| 337 | | 335 | |
| 338 | // As sym_index '0' is reserved, we use it for our stack pointer symbol | 336 | // create stack pointer symbol |
| 339 | const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer"); | 337 | { |
| 340 | const symbol = try wasm_bin.symbols.addOne(allocator); | 338 | const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global); |
| 341 | symbol.* = .{ | 339 | const symbol = loc.getSymbol(wasm_bin); |
| 342 | .name = sym_name, | 340 | // For object files we will import the stack pointer symbol |
| 343 | .tag = .global, | 341 | if (options.output_mode == .Obj) { |
| 344 | .flags = 0, | 342 | symbol.setUndefined(true); |
| 345 | .index = 0, | 343 | symbol.index = @intCast(u32, wasm_bin.imported_globals_count); |
| 346 | }; | 344 | wasm_bin.imported_globals_count += 1; |
| 347 | const loc: SymbolLoc = .{ .file = null, .index = 0 }; | 345 | try wasm_bin.imports.putNoClobber( |
| 348 | try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {}); | 346 | allocator, |
| 349 | try wasm_bin.globals.putNoClobber(allocator, sym_name, loc); | 347 | loc, |
| 350 | | 348 | .{ |
| 351 | // For object files we will import the stack pointer symbol | 349 | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), |
| 352 | if (options.output_mode == .Obj) { | 350 | .name = symbol.name, |
| 353 | symbol.setUndefined(true); | 351 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 354 | try wasm_bin.imports.putNoClobber( | 352 | }, |
| 355 | allocator, | 353 | ); |
| 356 | .{ .file = null, .index = 0 }, | 354 | } else { |
| 357 | .{ | 355 | symbol.index = @intCast(u32, wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); |
| 358 | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), | 356 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 359 | .name = sym_name, | 357 | const global = try wasm_bin.wasm_globals.addOne(allocator); |
| 360 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, | 358 | global.* = .{ |
| 361 | }, | 359 | .global_type = .{ |
| 362 | ); | 360 | .valtype = .i32, |
| 363 | } else { | 361 | .mutable = true, |
| 364 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); | 362 | }, |
| 365 | const global = try wasm_bin.wasm_globals.addOne(allocator); | 363 | .init = .{ .i32_const = 0 }, |
| 366 | global.* = .{ | 364 | }; |
| 367 | .global_type = .{ | 365 | } |
| 368 | .valtype = .i32, | 366 | } |
| 369 | .mutable = true, | 367 | |
| 370 | }, | 368 | // create indirect function pointer symbol |
| 371 | .init = .{ .i32_const = 0 }, | 369 | { |
| | 370 | const loc = try wasm_bin.createSyntheticSymbol("__indirect_function_table", .table); |
| | 371 | const symbol = loc.getSymbol(wasm_bin); |
| | 372 | const table: std.wasm.Table = .{ |
| | 373 | .limits = .{ .min = 0, .max = null }, // will be overwritten during `mapFunctionTable` |
| | 374 | .reftype = .funcref, |
| 372 | }; | 375 | }; |
| | 376 | if (options.output_mode == .Obj or options.import_table) { |
| | 377 | symbol.setUndefined(true); |
| | 378 | symbol.index = @intCast(u32, wasm_bin.imported_tables_count); |
| | 379 | wasm_bin.imported_tables_count += 1; |
| | 380 | try wasm_bin.imports.put(allocator, loc, .{ |
| | 381 | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), |
| | 382 | .name = symbol.name, |
| | 383 | .kind = .{ .table = table }, |
| | 384 | }); |
| | 385 | } else { |
| | 386 | symbol.index = @intCast(u32, wasm_bin.imported_tables_count + wasm_bin.tables.items.len); |
| | 387 | try wasm_bin.tables.append(allocator, table); |
| | 388 | if (options.export_table) { |
| | 389 | symbol.setFlag(.WASM_SYM_EXPORTED); |
| | 390 | } else { |
| | 391 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 392 | } |
| | 393 | } |
| 373 | } | 394 | } |
| 374 | | 395 | |
| 375 | if (!options.strip and options.module != null) { | 396 | if (!options.strip and options.module != null) { |
| ... | @@ -400,6 +421,22 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { | ... | @@ -400,6 +421,22 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 400 | return wasm; | 421 | return wasm; |
| 401 | } | 422 | } |
| 402 | | 423 | |
| | 424 | /// For a given name, creates a new global synthetic symbol. |
| | 425 | /// Leaves index undefined and the default flags (0). |
| | 426 | fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc { |
| | 427 | const name_offset = try wasm.string_table.put(wasm.base.allocator, name); |
| | 428 | const sym_index = @intCast(u32, wasm.symbols.items.len); |
| | 429 | const loc: SymbolLoc = .{ .index = sym_index, .file = null }; |
| | 430 | try wasm.symbols.append(wasm.base.allocator, .{ |
| | 431 | .name = name_offset, |
| | 432 | .flags = 0, |
| | 433 | .tag = tag, |
| | 434 | .index = undefined, |
| | 435 | }); |
| | 436 | try wasm.resolved_symbols.putNoClobber(wasm.base.allocator, loc, {}); |
| | 437 | try wasm.globals.putNoClobber(wasm.base.allocator, name_offset, loc); |
| | 438 | return loc; |
| | 439 | } |
| 403 | /// Initializes symbols and atoms for the debug sections | 440 | /// Initializes symbols and atoms for the debug sections |
| 404 | /// Initialization is only done when compiling Zig code. | 441 | /// Initialization is only done when compiling Zig code. |
| 405 | /// When Zig is invoked as a linker instead, the atoms | 442 | /// When Zig is invoked as a linker instead, the atoms |
| ... | @@ -766,6 +803,7 @@ fn validateFeatures( | ... | @@ -766,6 +803,7 @@ fn validateFeatures( |
| 766 | | 803 | |
| 767 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { | 804 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| 768 | if (wasm.base.options.output_mode == .Obj) return; | 805 | if (wasm.base.options.output_mode == .Obj) return; |
| | 806 | if (wasm.base.options.import_symbols) return; |
| 769 | | 807 | |
| 770 | var found_undefined_symbols = false; | 808 | var found_undefined_symbols = false; |
| 771 | for (wasm.undefs.values()) |undef| { | 809 | for (wasm.undefs.values()) |undef| { |
| ... | @@ -775,7 +813,12 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { | ... | @@ -775,7 +813,12 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| 775 | const file_name = if (undef.file) |file_index| name: { | 813 | const file_name = if (undef.file) |file_index| name: { |
| 776 | break :name wasm.objects.items[file_index].name; | 814 | break :name wasm.objects.items[file_index].name; |
| 777 | } else wasm.name; | 815 | } else wasm.name; |
| 778 | log.err("could not resolve undefined symbol '{s}'", .{undef.getName(wasm)}); | 816 | const import_name = if (undef.file) |file_index| name: { |
| | 817 | const obj = wasm.objects.items[file_index]; |
| | 818 | const name_index = obj.findImport(symbol.tag.externalType(), symbol.index).name; |
| | 819 | break :name obj.string_table.get(name_index); |
| | 820 | } else wasm.string_table.get(wasm.imports.get(undef).?.name); |
| | 821 | log.err("could not resolve undefined symbol '{s}'", .{import_name}); |
| 779 | log.err(" defined in '{s}'", .{file_name}); | 822 | log.err(" defined in '{s}'", .{file_name}); |
| 780 | } | 823 | } |
| 781 | } | 824 | } |
| ... | @@ -840,7 +883,6 @@ pub fn deinit(wasm: *Wasm) void { | ... | @@ -840,7 +883,6 @@ pub fn deinit(wasm: *Wasm) void { |
| 840 | wasm.func_types.deinit(gpa); | 883 | wasm.func_types.deinit(gpa); |
| 841 | wasm.functions.deinit(gpa); | 884 | wasm.functions.deinit(gpa); |
| 842 | wasm.wasm_globals.deinit(gpa); | 885 | wasm.wasm_globals.deinit(gpa); |
| 843 | wasm.address_globals.deinit(gpa); | | |
| 844 | wasm.function_table.deinit(gpa); | 886 | wasm.function_table.deinit(gpa); |
| 845 | wasm.tables.deinit(gpa); | 887 | wasm.tables.deinit(gpa); |
| 846 | wasm.exports.deinit(gpa); | 888 | wasm.exports.deinit(gpa); |
| ... | @@ -1249,7 +1291,7 @@ pub fn updateDeclExports( | ... | @@ -1249,7 +1291,7 @@ pub fn updateDeclExports( |
| 1249 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; | 1291 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; |
| 1250 | | 1292 | |
| 1251 | const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; | 1293 | const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; |
| 1252 | // When both the to-bo-exported symbol and the already existing symbol | 1294 | // When both the to-be-exported symbol and the already existing symbol |
| 1253 | // are strong symbols, we have a linker error. | 1295 | // are strong symbols, we have a linker error. |
| 1254 | // In the other case we replace one with the other. | 1296 | // In the other case we replace one with the other. |
| 1255 | if (!exp_is_weak and !existing_sym.isWeak()) { | 1297 | if (!exp_is_weak and !existing_sym.isWeak()) { |
| ... | @@ -1361,6 +1403,19 @@ fn mapFunctionTable(wasm: *Wasm) void { | ... | @@ -1361,6 +1403,19 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1361 | while (it.next()) |value_ptr| : (index += 1) { | 1403 | while (it.next()) |value_ptr| : (index += 1) { |
| 1362 | value_ptr.* = index; | 1404 | value_ptr.* = index; |
| 1363 | } | 1405 | } |
| | 1406 | |
| | 1407 | if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) { |
| | 1408 | const sym_loc = wasm.globals.get(wasm.string_table.getOffset("__indirect_function_table").?).?; |
| | 1409 | const import = wasm.imports.getPtr(sym_loc).?; |
| | 1410 | import.kind.table.limits.min = index - 1; // we start at index 1. |
| | 1411 | } else if (index > 1) { |
| | 1412 | log.debug("Appending indirect function table", .{}); |
| | 1413 | const offset = wasm.string_table.getOffset("__indirect_function_table").?; |
| | 1414 | const sym_with_loc = wasm.globals.get(offset).?; |
| | 1415 | const symbol = sym_with_loc.getSymbol(wasm); |
| | 1416 | const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count]; |
| | 1417 | table.limits = .{ .min = index, .max = index }; |
| | 1418 | } |
| 1364 | } | 1419 | } |
| 1365 | | 1420 | |
| 1366 | /// Either creates a new import, or updates one if existing. | 1421 | /// Either creates a new import, or updates one if existing. |
| ... | @@ -1380,18 +1435,31 @@ pub fn addOrUpdateImport( | ... | @@ -1380,18 +1435,31 @@ pub fn addOrUpdateImport( |
| 1380 | type_index: ?u32, | 1435 | type_index: ?u32, |
| 1381 | ) !void { | 1436 | ) !void { |
| 1382 | assert(symbol_index != 0); | 1437 | assert(symbol_index != 0); |
| 1383 | // For the import name itwasm, we use the decl's name, rather than the fully qualified name | 1438 | // For the import name, we use the decl's name, rather than the fully qualified name |
| 1384 | const decl_name_index = try wasm.string_table.put(wasm.base.allocator, name); | 1439 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| | 1440 | // name but different module can be resolved correctly. |
| | 1441 | const mangle_name = lib_name != null and |
| | 1442 | !std.mem.eql(u8, std.mem.sliceTo(lib_name.?, 0), "c"); |
| | 1443 | const full_name = if (mangle_name) full_name: { |
| | 1444 | break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); |
| | 1445 | } else name; |
| | 1446 | defer if (mangle_name) wasm.base.allocator.free(full_name); |
| | 1447 | |
| | 1448 | const decl_name_index = try wasm.string_table.put(wasm.base.allocator, full_name); |
| 1385 | const symbol: *Symbol = &wasm.symbols.items[symbol_index]; | 1449 | const symbol: *Symbol = &wasm.symbols.items[symbol_index]; |
| 1386 | symbol.setUndefined(true); | 1450 | symbol.setUndefined(true); |
| 1387 | symbol.setGlobal(true); | 1451 | symbol.setGlobal(true); |
| 1388 | symbol.name = decl_name_index; | 1452 | symbol.name = decl_name_index; |
| | 1453 | if (mangle_name) { |
| | 1454 | // we specified a specific name for the symbol that does not match the import name |
| | 1455 | symbol.setFlag(.WASM_SYM_EXPLICIT_NAME); |
| | 1456 | } |
| 1389 | const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index); | 1457 | const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index); |
| 1390 | if (!global_gop.found_existing) { | 1458 | if (!global_gop.found_existing) { |
| 1391 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; | 1459 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; |
| 1392 | global_gop.value_ptr.* = loc; | 1460 | global_gop.value_ptr.* = loc; |
| 1393 | try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); | 1461 | try wasm.resolved_symbols.put(wasm.base.allocator, loc, {}); |
| 1394 | try wasm.undefs.putNoClobber(wasm.base.allocator, name, loc); | 1462 | try wasm.undefs.putNoClobber(wasm.base.allocator, full_name, loc); |
| 1395 | } | 1463 | } |
| 1396 | | 1464 | |
| 1397 | if (type_index) |ty_index| { | 1465 | if (type_index) |ty_index| { |
| ... | @@ -1402,7 +1470,7 @@ pub fn addOrUpdateImport( | ... | @@ -1402,7 +1470,7 @@ pub fn addOrUpdateImport( |
| 1402 | if (!gop.found_existing) { | 1470 | if (!gop.found_existing) { |
| 1403 | gop.value_ptr.* = .{ | 1471 | gop.value_ptr.* = .{ |
| 1404 | .module_name = try wasm.string_table.put(wasm.base.allocator, module_name), | 1472 | .module_name = try wasm.string_table.put(wasm.base.allocator, module_name), |
| 1405 | .name = decl_name_index, | 1473 | .name = try wasm.string_table.put(wasm.base.allocator, name), |
| 1406 | .kind = .{ .function = ty_index }, | 1474 | .kind = .{ .function = ty_index }, |
| 1407 | }; | 1475 | }; |
| 1408 | } | 1476 | } |
| ... | @@ -1700,17 +1768,6 @@ fn setupImports(wasm: *Wasm) !void { | ... | @@ -1700,17 +1768,6 @@ fn setupImports(wasm: *Wasm) !void { |
| 1700 | /// Takes the global, function and table section from each linked object file | 1768 | /// Takes the global, function and table section from each linked object file |
| 1701 | /// and merges it into a single section for each. | 1769 | /// and merges it into a single section for each. |
| 1702 | fn mergeSections(wasm: *Wasm) !void { | 1770 | fn mergeSections(wasm: *Wasm) !void { |
| 1703 | // append the indirect function table if initialized | | |
| 1704 | if (wasm.string_table.getOffset("__indirect_function_table")) |offset| { | | |
| 1705 | const sym_loc = wasm.globals.get(offset).?; | | |
| 1706 | const table: std.wasm.Table = .{ | | |
| 1707 | .limits = .{ .min = @intCast(u32, wasm.function_table.count()), .max = null }, | | |
| 1708 | .reftype = .funcref, | | |
| 1709 | }; | | |
| 1710 | sym_loc.getSymbol(wasm).index = @intCast(u32, wasm.tables.items.len) + wasm.imported_tables_count; | | |
| 1711 | try wasm.tables.append(wasm.base.allocator, table); | | |
| 1712 | } | | |
| 1713 | | | |
| 1714 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 1771 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 1715 | if (sym_loc.file == null) { | 1772 | if (sym_loc.file == null) { |
| 1716 | // Zig code-generated symbols are already within the sections and do not | 1773 | // Zig code-generated symbols are already within the sections and do not |
| ... | @@ -1800,9 +1857,36 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -1800,9 +1857,36 @@ fn setupExports(wasm: *Wasm) !void { |
| 1800 | if (wasm.base.options.output_mode == .Obj) return; | 1857 | if (wasm.base.options.output_mode == .Obj) return; |
| 1801 | log.debug("Building exports from symbols", .{}); | 1858 | log.debug("Building exports from symbols", .{}); |
| 1802 | | 1859 | |
| | 1860 | const force_exp_names = wasm.base.options.export_symbol_names; |
| | 1861 | if (force_exp_names.len > 0) { |
| | 1862 | var failed_exports = try std.ArrayList([]const u8).initCapacity(wasm.base.allocator, force_exp_names.len); |
| | 1863 | defer failed_exports.deinit(); |
| | 1864 | |
| | 1865 | for (force_exp_names) |exp_name| { |
| | 1866 | const name_index = wasm.string_table.getOffset(exp_name) orelse { |
| | 1867 | failed_exports.appendAssumeCapacity(exp_name); |
| | 1868 | continue; |
| | 1869 | }; |
| | 1870 | const loc = wasm.globals.get(name_index) orelse { |
| | 1871 | failed_exports.appendAssumeCapacity(exp_name); |
| | 1872 | continue; |
| | 1873 | }; |
| | 1874 | |
| | 1875 | const symbol = loc.getSymbol(wasm); |
| | 1876 | symbol.setFlag(.WASM_SYM_EXPORTED); |
| | 1877 | } |
| | 1878 | |
| | 1879 | if (failed_exports.items.len > 0) { |
| | 1880 | for (failed_exports.items) |exp_name| { |
| | 1881 | log.err("could not export '{s}', symbol not found", .{exp_name}); |
| | 1882 | } |
| | 1883 | return error.MissingSymbol; |
| | 1884 | } |
| | 1885 | } |
| | 1886 | |
| 1803 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 1887 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 1804 | const symbol = sym_loc.getSymbol(wasm); | 1888 | const symbol = sym_loc.getSymbol(wasm); |
| 1805 | if (!symbol.isExported()) continue; | 1889 | if (!symbol.isExported(wasm.base.options.rdynamic)) continue; |
| 1806 | | 1890 | |
| 1807 | const sym_name = sym_loc.getName(wasm); | 1891 | const sym_name = sym_loc.getName(wasm); |
| 1808 | const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { | 1892 | const export_name = if (wasm.export_names.get(sym_loc)) |name| name else blk: { |
| ... | @@ -1810,8 +1894,13 @@ fn setupExports(wasm: *Wasm) !void { | ... | @@ -1810,8 +1894,13 @@ fn setupExports(wasm: *Wasm) !void { |
| 1810 | break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); | 1894 | break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); |
| 1811 | }; | 1895 | }; |
| 1812 | const exp: types.Export = if (symbol.tag == .data) exp: { | 1896 | const exp: types.Export = if (symbol.tag == .data) exp: { |
| 1813 | const global_index = @intCast(u32, wasm.wasm_globals.items.len + wasm.address_globals.items.len); | 1897 | const atom = wasm.symbol_atom.get(sym_loc).?; |
| 1814 | try wasm.address_globals.append(wasm.base.allocator, sym_loc); | 1898 | const va = atom.getVA(wasm, symbol); |
| | 1899 | const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len); |
| | 1900 | try wasm.wasm_globals.append(wasm.base.allocator, .{ |
| | 1901 | .global_type = .{ .valtype = .i32, .mutable = false }, |
| | 1902 | .init = .{ .i32_const = @intCast(i32, va) }, |
| | 1903 | }); |
| 1815 | break :exp .{ | 1904 | break :exp .{ |
| 1816 | .name = export_name, | 1905 | .name = export_name, |
| 1817 | .kind = .global, | 1906 | .kind = .global, |
| ... | @@ -2399,6 +2488,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l | ... | @@ -2399,6 +2488,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2399 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; | 2488 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; |
| 2400 | try wasm.validateFeatures(&enabled_features, &emit_features_count); | 2489 | try wasm.validateFeatures(&enabled_features, &emit_features_count); |
| 2401 | try wasm.resolveSymbolsInArchives(); | 2490 | try wasm.resolveSymbolsInArchives(); |
| | 2491 | try wasm.checkUndefinedSymbols(); |
| 2402 | | 2492 | |
| 2403 | try wasm.setupStart(); | 2493 | try wasm.setupStart(); |
| 2404 | try wasm.setupImports(); | 2494 | try wasm.setupImports(); |
| ... | @@ -2586,28 +2676,9 @@ fn writeToFile( | ... | @@ -2586,28 +2676,9 @@ fn writeToFile( |
| 2586 | | 2676 | |
| 2587 | // Import section | 2677 | // Import section |
| 2588 | const import_memory = wasm.base.options.import_memory or is_obj; | 2678 | const import_memory = wasm.base.options.import_memory or is_obj; |
| 2589 | const import_table = wasm.base.options.import_table or is_obj; | 2679 | if (wasm.imports.count() != 0 or import_memory) { |
| 2590 | if (wasm.imports.count() != 0 or import_memory or import_table) { | | |
| 2591 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2680 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2592 | | 2681 | |
| 2593 | // import table is always first table so emit that first | | |
| 2594 | if (import_table) { | | |
| 2595 | const table_imp: types.Import = .{ | | |
| 2596 | .module_name = try wasm.string_table.put(wasm.base.allocator, wasm.host_name), | | |
| 2597 | .name = try wasm.string_table.put(wasm.base.allocator, "__indirect_function_table"), | | |
| 2598 | .kind = .{ | | |
| 2599 | .table = .{ | | |
| 2600 | .limits = .{ | | |
| 2601 | .min = @intCast(u32, wasm.function_table.count()), | | |
| 2602 | .max = null, | | |
| 2603 | }, | | |
| 2604 | .reftype = .funcref, | | |
| 2605 | }, | | |
| 2606 | }, | | |
| 2607 | }; | | |
| 2608 | try wasm.emitImport(binary_writer, table_imp); | | |
| 2609 | } | | |
| 2610 | | | |
| 2611 | var it = wasm.imports.iterator(); | 2682 | var it = wasm.imports.iterator(); |
| 2612 | while (it.next()) |entry| { | 2683 | while (it.next()) |entry| { |
| 2613 | assert(entry.key_ptr.*.getSymbol(wasm).isUndefined()); | 2684 | assert(entry.key_ptr.*.getSymbol(wasm).isUndefined()); |
| ... | @@ -2630,7 +2701,7 @@ fn writeToFile( | ... | @@ -2630,7 +2701,7 @@ fn writeToFile( |
| 2630 | header_offset, | 2701 | header_offset, |
| 2631 | .import, | 2702 | .import, |
| 2632 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), | 2703 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2633 | @intCast(u32, wasm.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)), | 2704 | @intCast(u32, wasm.imports.count() + @boolToInt(import_memory)), |
| 2634 | ); | 2705 | ); |
| 2635 | section_count += 1; | 2706 | section_count += 1; |
| 2636 | } | 2707 | } |
| ... | @@ -2653,22 +2724,20 @@ fn writeToFile( | ... | @@ -2653,22 +2724,20 @@ fn writeToFile( |
| 2653 | } | 2724 | } |
| 2654 | | 2725 | |
| 2655 | // Table section | 2726 | // Table section |
| 2656 | const export_table = wasm.base.options.export_table; | 2727 | if (wasm.tables.items.len > 0) { |
| 2657 | if (!import_table and wasm.function_table.count() != 0) { | | |
| 2658 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2728 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2659 | | 2729 | |
| 2660 | try leb.writeULEB128(binary_writer, std.wasm.reftype(.funcref)); | 2730 | for (wasm.tables.items) |table| { |
| 2661 | try emitLimits(binary_writer, .{ | 2731 | try leb.writeULEB128(binary_writer, std.wasm.reftype(table.reftype)); |
| 2662 | .min = @intCast(u32, wasm.function_table.count()) + 1, | 2732 | try emitLimits(binary_writer, table.limits); |
| 2663 | .max = null, | 2733 | } |
| 2664 | }); | | |
| 2665 | | 2734 | |
| 2666 | try writeVecSectionHeader( | 2735 | try writeVecSectionHeader( |
| 2667 | binary_bytes.items, | 2736 | binary_bytes.items, |
| 2668 | header_offset, | 2737 | header_offset, |
| 2669 | .table, | 2738 | .table, |
| 2670 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), | 2739 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2671 | @as(u32, 1), | 2740 | @intCast(u32, wasm.tables.items.len), |
| 2672 | ); | 2741 | ); |
| 2673 | section_count += 1; | 2742 | section_count += 1; |
| 2674 | } | 2743 | } |
| ... | @@ -2692,22 +2761,10 @@ fn writeToFile( | ... | @@ -2692,22 +2761,10 @@ fn writeToFile( |
| 2692 | if (wasm.wasm_globals.items.len > 0) { | 2761 | if (wasm.wasm_globals.items.len > 0) { |
| 2693 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2762 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2694 | | 2763 | |
| 2695 | var global_count: u32 = 0; | | |
| 2696 | for (wasm.wasm_globals.items) |global| { | 2764 | for (wasm.wasm_globals.items) |global| { |
| 2697 | try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype)); | 2765 | try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype)); |
| 2698 | try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); | 2766 | try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); |
| 2699 | try emitInit(binary_writer, global.init); | 2767 | try emitInit(binary_writer, global.init); |
| 2700 | global_count += 1; | | |
| 2701 | } | | |
| 2702 | | | |
| 2703 | for (wasm.address_globals.items) |sym_loc| { | | |
| 2704 | const atom = wasm.symbol_atom.get(sym_loc).?; | | |
| 2705 | try binary_writer.writeByte(std.wasm.valtype(.i32)); | | |
| 2706 | try binary_writer.writeByte(0); // immutable | | |
| 2707 | try emitInit(binary_writer, .{ | | |
| 2708 | .i32_const = @bitCast(i32, atom.offset), | | |
| 2709 | }); | | |
| 2710 | global_count += 1; | | |
| 2711 | } | 2768 | } |
| 2712 | | 2769 | |
| 2713 | try writeVecSectionHeader( | 2770 | try writeVecSectionHeader( |
| ... | @@ -2715,13 +2772,13 @@ fn writeToFile( | ... | @@ -2715,13 +2772,13 @@ fn writeToFile( |
| 2715 | header_offset, | 2772 | header_offset, |
| 2716 | .global, | 2773 | .global, |
| 2717 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), | 2774 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2718 | @intCast(u32, global_count), | 2775 | @intCast(u32, wasm.wasm_globals.items.len), |
| 2719 | ); | 2776 | ); |
| 2720 | section_count += 1; | 2777 | section_count += 1; |
| 2721 | } | 2778 | } |
| 2722 | | 2779 | |
| 2723 | // Export section | 2780 | // Export section |
| 2724 | if (wasm.exports.items.len != 0 or export_table or !import_memory) { | 2781 | if (wasm.exports.items.len != 0 or !import_memory) { |
| 2725 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2782 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2726 | | 2783 | |
| 2727 | for (wasm.exports.items) |exp| { | 2784 | for (wasm.exports.items) |exp| { |
| ... | @@ -2732,13 +2789,6 @@ fn writeToFile( | ... | @@ -2732,13 +2789,6 @@ fn writeToFile( |
| 2732 | try leb.writeULEB128(binary_writer, exp.index); | 2789 | try leb.writeULEB128(binary_writer, exp.index); |
| 2733 | } | 2790 | } |
| 2734 | | 2791 | |
| 2735 | if (export_table) { | | |
| 2736 | try leb.writeULEB128(binary_writer, @intCast(u32, "__indirect_function_table".len)); | | |
| 2737 | try binary_writer.writeAll("__indirect_function_table"); | | |
| 2738 | try binary_writer.writeByte(std.wasm.externalKind(.table)); | | |
| 2739 | try leb.writeULEB128(binary_writer, @as(u32, 0)); // function table is always the first table | | |
| 2740 | } | | |
| 2741 | | | |
| 2742 | if (!import_memory) { | 2792 | if (!import_memory) { |
| 2743 | try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len)); | 2793 | try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len)); |
| 2744 | try binary_writer.writeAll("memory"); | 2794 | try binary_writer.writeAll("memory"); |
| ... | @@ -2751,7 +2801,7 @@ fn writeToFile( | ... | @@ -2751,7 +2801,7 @@ fn writeToFile( |
| 2751 | header_offset, | 2801 | header_offset, |
| 2752 | .@"export", | 2802 | .@"export", |
| 2753 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), | 2803 | @intCast(u32, binary_bytes.items.len - header_offset - header_size), |
| 2754 | @intCast(u32, wasm.exports.items.len) + @boolToInt(export_table) + @boolToInt(!import_memory), | 2804 | @intCast(u32, wasm.exports.items.len) + @boolToInt(!import_memory), |
| 2755 | ); | 2805 | ); |
| 2756 | section_count += 1; | 2806 | section_count += 1; |
| 2757 | } | 2807 | } |
| ... | @@ -2760,11 +2810,18 @@ fn writeToFile( | ... | @@ -2760,11 +2810,18 @@ fn writeToFile( |
| 2760 | if (wasm.function_table.count() > 0) { | 2810 | if (wasm.function_table.count() > 0) { |
| 2761 | const header_offset = try reserveVecSectionHeader(&binary_bytes); | 2811 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2762 | | 2812 | |
| 2763 | var flags: u32 = 0x2; // Yes we have a table | 2813 | const table_loc = wasm.globals.get(wasm.string_table.getOffset("__indirect_function_table").?).?; |
| | 2814 | const table_sym = table_loc.getSymbol(wasm); |
| | 2815 | |
| | 2816 | var flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually |
| 2764 | try leb.writeULEB128(binary_writer, flags); | 2817 | try leb.writeULEB128(binary_writer, flags); |
| 2765 | try leb.writeULEB128(binary_writer, @as(u32, 0)); // index of that table. TODO: Store synthetic symbols | 2818 | if (flags == 0x02) { |
| | 2819 | try leb.writeULEB128(binary_writer, table_sym.index); |
| | 2820 | } |
| 2766 | try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid | 2821 | try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid |
| 2767 | try leb.writeULEB128(binary_writer, @as(u8, 0)); | 2822 | if (flags == 0x02) { |
| | 2823 | try leb.writeULEB128(binary_writer, @as(u8, 0)); // represents funcref |
| | 2824 | } |
| 2768 | try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count())); | 2825 | try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count())); |
| 2769 | var symbol_it = wasm.function_table.keyIterator(); | 2826 | var symbol_it = wasm.function_table.keyIterator(); |
| 2770 | while (symbol_it.next()) |symbol_loc_ptr| { | 2827 | while (symbol_it.next()) |symbol_loc_ptr| { |
| ... | @@ -3091,11 +3148,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem | ... | @@ -3091,11 +3148,7 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem |
| 3091 | | 3148 | |
| 3092 | for (wasm.resolved_symbols.keys()) |sym_loc| { | 3149 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 3093 | const symbol = sym_loc.getSymbol(wasm).*; | 3150 | const symbol = sym_loc.getSymbol(wasm).*; |
| 3094 | const name = if (symbol.isUndefined()) blk: { | 3151 | const name = sym_loc.getName(wasm); |
| 3095 | if (symbol.tag == .data) continue; | | |
| 3096 | const imp = wasm.imports.get(sym_loc) orelse continue; | | |
| 3097 | break :blk wasm.string_table.get(imp.name); | | |
| 3098 | } else sym_loc.getName(wasm); | | |
| 3099 | switch (symbol.tag) { | 3152 | switch (symbol.tag) { |
| 3100 | .function => { | 3153 | .function => { |
| 3101 | const gop = funcs.getOrPutAssumeCapacity(symbol.index); | 3154 | const gop = funcs.getOrPutAssumeCapacity(symbol.index); |