| ... | ... | @@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, |
| 112 | 112 | functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{}, |
| 113 | 113 | /// Output global section |
| 114 | 114 | wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, |
| 115 | | /// Global symbols for exported data symbols |
| 116 | | address_globals: std.ArrayListUnmanaged(SymbolLoc) = .{}, |
| 117 | 115 | /// Memory section |
| 118 | 116 | memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, |
| 119 | 117 | /// Output table section |
| ... | ... | @@ -335,41 +333,64 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 335 | 333 | wasm_bin.base.file = file; |
| 336 | 334 | wasm_bin.name = sub_path; |
| 337 | 335 | |
| 338 | | // As sym_index '0' is reserved, we use it for our stack pointer symbol |
| 339 | | const sym_name = try wasm_bin.string_table.put(allocator, "__stack_pointer"); |
| 340 | | const symbol = try wasm_bin.symbols.addOne(allocator); |
| 341 | | symbol.* = .{ |
| 342 | | .name = sym_name, |
| 343 | | .tag = .global, |
| 344 | | .flags = 0, |
| 345 | | .index = 0, |
| 346 | | }; |
| 347 | | const loc: SymbolLoc = .{ .file = null, .index = 0 }; |
| 348 | | try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {}); |
| 349 | | try wasm_bin.globals.putNoClobber(allocator, sym_name, loc); |
| 350 | | |
| 351 | | // For object files we will import the stack pointer symbol |
| 352 | | if (options.output_mode == .Obj) { |
| 353 | | symbol.setUndefined(true); |
| 354 | | try wasm_bin.imports.putNoClobber( |
| 355 | | allocator, |
| 356 | | .{ .file = null, .index = 0 }, |
| 357 | | .{ |
| 358 | | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), |
| 359 | | .name = sym_name, |
| 360 | | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 361 | | }, |
| 362 | | ); |
| 363 | | } else { |
| 364 | | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 365 | | const global = try wasm_bin.wasm_globals.addOne(allocator); |
| 366 | | global.* = .{ |
| 367 | | .global_type = .{ |
| 368 | | .valtype = .i32, |
| 369 | | .mutable = true, |
| 370 | | }, |
| 371 | | .init = .{ .i32_const = 0 }, |
| 336 | // create stack pointer symbol |
| 337 | { |
| 338 | const loc = try wasm_bin.createSyntheticSymbol("__stack_pointer", .global); |
| 339 | const symbol = loc.getSymbol(wasm_bin); |
| 340 | // For object files we will import the stack pointer symbol |
| 341 | if (options.output_mode == .Obj) { |
| 342 | symbol.setUndefined(true); |
| 343 | symbol.index = @intCast(u32, wasm_bin.imported_globals_count); |
| 344 | wasm_bin.imported_globals_count += 1; |
| 345 | try wasm_bin.imports.putNoClobber( |
| 346 | allocator, |
| 347 | loc, |
| 348 | .{ |
| 349 | .module_name = try wasm_bin.string_table.put(allocator, wasm_bin.host_name), |
| 350 | .name = symbol.name, |
| 351 | .kind = .{ .global = .{ .valtype = .i32, .mutable = true } }, |
| 352 | }, |
| 353 | ); |
| 354 | } else { |
| 355 | symbol.index = @intCast(u32, wasm_bin.imported_globals_count + wasm_bin.wasm_globals.items.len); |
| 356 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 357 | const global = try wasm_bin.wasm_globals.addOne(allocator); |
| 358 | global.* = .{ |
| 359 | .global_type = .{ |
| 360 | .valtype = .i32, |
| 361 | .mutable = true, |
| 362 | }, |
| 363 | .init = .{ .i32_const = 0 }, |
| 364 | }; |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | // create indirect function pointer symbol |
| 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 | 396 | if (!options.strip and options.module != null) { |
| ... | ... | @@ -400,6 +421,22 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { |
| 400 | 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 | 440 | /// Initializes symbols and atoms for the debug sections |
| 404 | 441 | /// Initialization is only done when compiling Zig code. |
| 405 | 442 | /// When Zig is invoked as a linker instead, the atoms |
| ... | ... | @@ -766,6 +803,7 @@ fn validateFeatures( |
| 766 | 803 | |
| 767 | 804 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| 768 | 805 | if (wasm.base.options.output_mode == .Obj) return; |
| 806 | if (wasm.base.options.import_symbols) return; |
| 769 | 807 | |
| 770 | 808 | var found_undefined_symbols = false; |
| 771 | 809 | for (wasm.undefs.values()) |undef| { |
| ... | ... | @@ -775,7 +813,12 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| 775 | 813 | const file_name = if (undef.file) |file_index| name: { |
| 776 | 814 | break :name wasm.objects.items[file_index].name; |
| 777 | 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 | 822 | log.err(" defined in '{s}'", .{file_name}); |
| 780 | 823 | } |
| 781 | 824 | } |
| ... | ... | @@ -840,7 +883,6 @@ pub fn deinit(wasm: *Wasm) void { |
| 840 | 883 | wasm.func_types.deinit(gpa); |
| 841 | 884 | wasm.functions.deinit(gpa); |
| 842 | 885 | wasm.wasm_globals.deinit(gpa); |
| 843 | | wasm.address_globals.deinit(gpa); |
| 844 | 886 | wasm.function_table.deinit(gpa); |
| 845 | 887 | wasm.tables.deinit(gpa); |
| 846 | 888 | wasm.exports.deinit(gpa); |
| ... | ... | @@ -1249,7 +1291,7 @@ pub fn updateDeclExports( |
| 1249 | 1291 | const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; |
| 1250 | 1292 | |
| 1251 | 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 | 1295 | // are strong symbols, we have a linker error. |
| 1254 | 1296 | // In the other case we replace one with the other. |
| 1255 | 1297 | if (!exp_is_weak and !existing_sym.isWeak()) { |
| ... | ... | @@ -1361,6 +1403,19 @@ fn mapFunctionTable(wasm: *Wasm) void { |
| 1361 | 1403 | while (it.next()) |value_ptr| : (index += 1) { |
| 1362 | 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 | 1421 | /// Either creates a new import, or updates one if existing. |
| ... | ... | @@ -1380,18 +1435,31 @@ pub fn addOrUpdateImport( |
| 1380 | 1435 | type_index: ?u32, |
| 1381 | 1436 | ) !void { |
| 1382 | 1437 | assert(symbol_index != 0); |
| 1383 | | // For the import name itwasm, 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); |
| 1438 | // For the import name, we use the decl's name, rather than the fully qualified 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 | 1449 | const symbol: *Symbol = &wasm.symbols.items[symbol_index]; |
| 1386 | 1450 | symbol.setUndefined(true); |
| 1387 | 1451 | symbol.setGlobal(true); |
| 1388 | 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 | 1457 | const global_gop = try wasm.globals.getOrPut(wasm.base.allocator, decl_name_index); |
| 1390 | 1458 | if (!global_gop.found_existing) { |
| 1391 | 1459 | const loc: SymbolLoc = .{ .file = null, .index = symbol_index }; |
| 1392 | 1460 | global_gop.value_ptr.* = loc; |
| 1393 | 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 | 1465 | if (type_index) |ty_index| { |
| ... | ... | @@ -1402,7 +1470,7 @@ pub fn addOrUpdateImport( |
| 1402 | 1470 | if (!gop.found_existing) { |
| 1403 | 1471 | gop.value_ptr.* = .{ |
| 1404 | 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 | 1474 | .kind = .{ .function = ty_index }, |
| 1407 | 1475 | }; |
| 1408 | 1476 | } |
| ... | ... | @@ -1700,17 +1768,6 @@ fn setupImports(wasm: *Wasm) !void { |
| 1700 | 1768 | /// Takes the global, function and table section from each linked object file |
| 1701 | 1769 | /// and merges it into a single section for each. |
| 1702 | 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 | 1771 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 1715 | 1772 | if (sym_loc.file == null) { |
| 1716 | 1773 | // Zig code-generated symbols are already within the sections and do not |
| ... | ... | @@ -1800,9 +1857,36 @@ fn setupExports(wasm: *Wasm) !void { |
| 1800 | 1857 | if (wasm.base.options.output_mode == .Obj) return; |
| 1801 | 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 | 1887 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 1804 | 1888 | const symbol = sym_loc.getSymbol(wasm); |
| 1805 | | if (!symbol.isExported()) continue; |
| 1889 | if (!symbol.isExported(wasm.base.options.rdynamic)) continue; |
| 1806 | 1890 | |
| 1807 | 1891 | const sym_name = sym_loc.getName(wasm); |
| 1808 | 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 | 1894 | break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); |
| 1811 | 1895 | }; |
| 1812 | 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); |
| 1814 | | try wasm.address_globals.append(wasm.base.allocator, sym_loc); |
| 1897 | const atom = wasm.symbol_atom.get(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 | 1904 | break :exp .{ |
| 1816 | 1905 | .name = export_name, |
| 1817 | 1906 | .kind = .global, |
| ... | ... | @@ -2399,6 +2488,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 2399 | 2488 | var enabled_features: [@typeInfo(types.Feature.Tag).Enum.fields.len]bool = undefined; |
| 2400 | 2489 | try wasm.validateFeatures(&enabled_features, &emit_features_count); |
| 2401 | 2490 | try wasm.resolveSymbolsInArchives(); |
| 2491 | try wasm.checkUndefinedSymbols(); |
| 2402 | 2492 | |
| 2403 | 2493 | try wasm.setupStart(); |
| 2404 | 2494 | try wasm.setupImports(); |
| ... | ... | @@ -2586,28 +2676,9 @@ fn writeToFile( |
| 2586 | 2676 | |
| 2587 | 2677 | // Import section |
| 2588 | 2678 | const import_memory = wasm.base.options.import_memory or is_obj; |
| 2589 | | const import_table = wasm.base.options.import_table or is_obj; |
| 2590 | | if (wasm.imports.count() != 0 or import_memory or import_table) { |
| 2679 | if (wasm.imports.count() != 0 or import_memory) { |
| 2591 | 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 | 2682 | var it = wasm.imports.iterator(); |
| 2612 | 2683 | while (it.next()) |entry| { |
| 2613 | 2684 | assert(entry.key_ptr.*.getSymbol(wasm).isUndefined()); |
| ... | ... | @@ -2630,7 +2701,7 @@ fn writeToFile( |
| 2630 | 2701 | header_offset, |
| 2631 | 2702 | .import, |
| 2632 | 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 | 2706 | section_count += 1; |
| 2636 | 2707 | } |
| ... | ... | @@ -2653,22 +2724,20 @@ fn writeToFile( |
| 2653 | 2724 | } |
| 2654 | 2725 | |
| 2655 | 2726 | // Table section |
| 2656 | | const export_table = wasm.base.options.export_table; |
| 2657 | | if (!import_table and wasm.function_table.count() != 0) { |
| 2727 | if (wasm.tables.items.len > 0) { |
| 2658 | 2728 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2659 | 2729 | |
| 2660 | | try leb.writeULEB128(binary_writer, std.wasm.reftype(.funcref)); |
| 2661 | | try emitLimits(binary_writer, .{ |
| 2662 | | .min = @intCast(u32, wasm.function_table.count()) + 1, |
| 2663 | | .max = null, |
| 2664 | | }); |
| 2730 | for (wasm.tables.items) |table| { |
| 2731 | try leb.writeULEB128(binary_writer, std.wasm.reftype(table.reftype)); |
| 2732 | try emitLimits(binary_writer, table.limits); |
| 2733 | } |
| 2665 | 2734 | |
| 2666 | 2735 | try writeVecSectionHeader( |
| 2667 | 2736 | binary_bytes.items, |
| 2668 | 2737 | header_offset, |
| 2669 | 2738 | .table, |
| 2670 | 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 | 2742 | section_count += 1; |
| 2674 | 2743 | } |
| ... | ... | @@ -2692,22 +2761,10 @@ fn writeToFile( |
| 2692 | 2761 | if (wasm.wasm_globals.items.len > 0) { |
| 2693 | 2762 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2694 | 2763 | |
| 2695 | | var global_count: u32 = 0; |
| 2696 | 2764 | for (wasm.wasm_globals.items) |global| { |
| 2697 | 2765 | try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype)); |
| 2698 | 2766 | try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); |
| 2699 | 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 | 2770 | try writeVecSectionHeader( |
| ... | ... | @@ -2715,13 +2772,13 @@ fn writeToFile( |
| 2715 | 2772 | header_offset, |
| 2716 | 2773 | .global, |
| 2717 | 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 | 2777 | section_count += 1; |
| 2721 | 2778 | } |
| 2722 | 2779 | |
| 2723 | 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 | 2782 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 2726 | 2783 | |
| 2727 | 2784 | for (wasm.exports.items) |exp| { |
| ... | ... | @@ -2732,13 +2789,6 @@ fn writeToFile( |
| 2732 | 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 | 2792 | if (!import_memory) { |
| 2743 | 2793 | try leb.writeULEB128(binary_writer, @intCast(u32, "memory".len)); |
| 2744 | 2794 | try binary_writer.writeAll("memory"); |
| ... | ... | @@ -2751,7 +2801,7 @@ fn writeToFile( |
| 2751 | 2801 | header_offset, |
| 2752 | 2802 | .@"export", |
| 2753 | 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 | 2806 | section_count += 1; |
| 2757 | 2807 | } |
| ... | ... | @@ -2760,11 +2810,18 @@ fn writeToFile( |
| 2760 | 2810 | if (wasm.function_table.count() > 0) { |
| 2761 | 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 | 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 | 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 | 2825 | try leb.writeULEB128(binary_writer, @intCast(u32, wasm.function_table.count())); |
| 2769 | 2826 | var symbol_it = wasm.function_table.keyIterator(); |
| 2770 | 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 | 3148 | |
| 3092 | 3149 | for (wasm.resolved_symbols.keys()) |sym_loc| { |
| 3093 | 3150 | const symbol = sym_loc.getSymbol(wasm).*; |
| 3094 | | const name = if (symbol.isUndefined()) blk: { |
| 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); |
| 3151 | const name = sym_loc.getName(wasm); |
| 3099 | 3152 | switch (symbol.tag) { |
| 3100 | 3153 | .function => { |
| 3101 | 3154 | const gop = funcs.getOrPutAssumeCapacity(symbol.index); |