| ... | ... | @@ -124,6 +124,8 @@ exports: std.ArrayListUnmanaged(types.Export) = .{}, |
| 124 | 124 | /// List of initialization functions. These must be called in order of priority |
| 125 | 125 | /// by the (synthetic) __wasm_call_ctors function. |
| 126 | 126 | init_funcs: std.ArrayListUnmanaged(InitFuncLoc) = .{}, |
| 127 | /// Index to a function defining the entry of the wasm file |
| 128 | entry: ?u32 = null, |
| 127 | 129 | |
| 128 | 130 | /// Indirect function table, used to call function pointers |
| 129 | 131 | /// When this is non-zero, we must emit a table entry, |
| ... | ... | @@ -477,7 +479,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 477 | 479 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 478 | 480 | } |
| 479 | 481 | { |
| 480 | | const loc = try wasm_bin.createSyntheticSymbol("__wasm_tls_init", .function); |
| 482 | const loc = try wasm_bin.createSyntheticSymbol("__wasm_init_tls", .function); |
| 481 | 483 | const symbol = loc.getSymbol(wasm_bin); |
| 482 | 484 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| 483 | 485 | } |
| ... | ... | @@ -843,6 +845,12 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 843 | 845 | } |
| 844 | 846 | } |
| 845 | 847 | |
| 848 | /// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value. |
| 849 | fn writeI32Const(writer: anytype, val: u32) !void { |
| 850 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 851 | try leb.writeILEB128(writer, @as(i32, @bitCast(val))); |
| 852 | } |
| 853 | |
| 846 | 854 | fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 847 | 855 | // Passive segments are used to avoid memory being reinitialized on each |
| 848 | 856 | // thread's instantiation. These passive segments are initialized and |
| ... | ... | @@ -880,12 +888,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 880 | 888 | try writer.writeByte(std.wasm.block_empty); // block type |
| 881 | 889 | |
| 882 | 890 | // atomically check |
| 883 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 884 | | try leb.writeULEB128(writer, flag_address); |
| 885 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 886 | | try leb.writeULEB128(writer, @as(u32, 0)); |
| 887 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 888 | | try leb.writeULEB128(writer, @as(u32, 1)); |
| 891 | try writeI32Const(writer, flag_address); |
| 892 | try writeI32Const(writer, 0); |
| 893 | try writeI32Const(writer, 1); |
| 889 | 894 | try writer.writeByte(std.wasm.opcode(.atomics_prefix)); |
| 890 | 895 | try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.i32_atomic_rmw_cmpxchg)); |
| 891 | 896 | try leb.writeULEB128(writer, @as(u32, 2)); // alignment |
| ... | ... | @@ -909,24 +914,20 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 909 | 914 | // For non-BSS segments we do a memory.init. Both these |
| 910 | 915 | // instructions take as their first argument the destination |
| 911 | 916 | // address. |
| 912 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 913 | | try leb.writeULEB128(writer, segment.offset); |
| 917 | try writeI32Const(writer, segment.offset); |
| 914 | 918 | |
| 915 | 919 | if (wasm.base.options.shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) { |
| 916 | 920 | // When we initialize the TLS segment we also set the `__tls_base` |
| 917 | 921 | // global. This allows the runtime to use this static copy of the |
| 918 | 922 | // TLS data for the first/main thread. |
| 919 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 920 | | try leb.writeULEB128(writer, segment.offset); |
| 923 | try writeI32Const(writer, segment.offset); |
| 921 | 924 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 922 | 925 | const loc = wasm.findGlobalSymbol("__tls_base").?; |
| 923 | 926 | try leb.writeULEB128(writer, loc.getSymbol(wasm).index); |
| 924 | 927 | } |
| 925 | 928 | |
| 926 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 927 | | try leb.writeULEB128(writer, @as(u32, 0)); |
| 928 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 929 | | try leb.writeULEB128(writer, segment.size); |
| 929 | try writeI32Const(writer, 0); |
| 930 | try writeI32Const(writer, segment.size); |
| 930 | 931 | try writer.writeByte(std.wasm.opcode(.misc_prefix)); |
| 931 | 932 | if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) { |
| 932 | 933 | // fill bss segment with zeroes |
| ... | ... | @@ -942,18 +943,15 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 942 | 943 | |
| 943 | 944 | if (wasm.base.options.shared_memory) { |
| 944 | 945 | // we set the init memory flag to value '2' |
| 945 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 946 | | try leb.writeULEB128(writer, flag_address); |
| 947 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 948 | | try leb.writeULEB128(writer, @as(u32, 2)); |
| 946 | try writeI32Const(writer, flag_address); |
| 947 | try writeI32Const(writer, 2); |
| 949 | 948 | try writer.writeByte(std.wasm.opcode(.atomics_prefix)); |
| 950 | 949 | try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.i32_atomic_store)); |
| 951 | 950 | try leb.writeULEB128(writer, @as(u32, 2)); // alignment |
| 952 | 951 | try leb.writeULEB128(writer, @as(u32, 0)); // offset |
| 953 | 952 | |
| 954 | 953 | // notify any waiters for segment initialization completion |
| 955 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 956 | | try leb.writeULEB128(writer, flag_address); |
| 954 | try writeI32Const(writer, flag_address); |
| 957 | 955 | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 958 | 956 | try leb.writeILEB128(writer, @as(i32, -1)); // number of waiters |
| 959 | 957 | try writer.writeByte(std.wasm.opcode(.atomics_prefix)); |
| ... | ... | @@ -968,12 +966,10 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void { |
| 968 | 966 | |
| 969 | 967 | // wait for thread to initialize memory segments |
| 970 | 968 | try writer.writeByte(std.wasm.opcode(.end)); // end $wait |
| 971 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 972 | | try leb.writeULEB128(writer, flag_address); |
| 973 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 974 | | try leb.writeULEB128(writer, @as(u32, 1)); // expected flag value |
| 975 | | try writer.writeByte(std.wasm.opcode(.i32_const)); |
| 976 | | try leb.writeILEB128(writer, @as(i32, -1)); // timeout |
| 969 | try writeI32Const(writer, flag_address); |
| 970 | try writeI32Const(writer, 1); // expected flag value |
| 971 | try writer.writeByte(std.wasm.opcode(.i64_const)); |
| 972 | try leb.writeILEB128(writer, @as(i64, -1)); // timeout |
| 977 | 973 | try writer.writeByte(std.wasm.opcode(.atomics_prefix)); |
| 978 | 974 | try leb.writeULEB128(writer, std.wasm.atomicsOpcode(.memory_atomic_wait32)); |
| 979 | 975 | try leb.writeULEB128(writer, @as(u32, 2)); // alignment |
| ... | ... | @@ -2174,7 +2170,7 @@ fn sortDataSegments(wasm: *Wasm) !void { |
| 2174 | 2170 | |
| 2175 | 2171 | const SortContext = struct { |
| 2176 | 2172 | fn sort(_: void, lhs: []const u8, rhs: []const u8) bool { |
| 2177 | | return order(lhs) <= order(rhs); |
| 2173 | return order(lhs) < order(rhs); |
| 2178 | 2174 | } |
| 2179 | 2175 | |
| 2180 | 2176 | fn order(name: []const u8) u8 { |
| ... | ... | @@ -2405,6 +2401,13 @@ pub fn createFunction( |
| 2405 | 2401 | return loc.index; |
| 2406 | 2402 | } |
| 2407 | 2403 | |
| 2404 | /// If required, sets the function index in the `start` section. |
| 2405 | fn setupStartSection(wasm: *Wasm) !void { |
| 2406 | if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| { |
| 2407 | wasm.entry = loc.getSymbol(wasm).index; |
| 2408 | } |
| 2409 | } |
| 2410 | |
| 2408 | 2411 | fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2409 | 2412 | if (!wasm.base.options.shared_memory) return; |
| 2410 | 2413 | |
| ... | ... | @@ -2426,7 +2429,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void { |
| 2426 | 2429 | try leb.writeULEB128(writer, param_local); |
| 2427 | 2430 | |
| 2428 | 2431 | const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?; |
| 2429 | | try writer.writeByte(std.wasm.opcode(.global_get)); |
| 2432 | try writer.writeByte(std.wasm.opcode(.global_set)); |
| 2430 | 2433 | try leb.writeULEB128(writer, tls_base_loc.getSymbol(wasm).index); |
| 2431 | 2434 | |
| 2432 | 2435 | // load stack values for the bulk-memory operation |
| ... | ... | @@ -3329,6 +3332,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l |
| 3329 | 3332 | try wasm.setupInitMemoryFunction(); |
| 3330 | 3333 | try wasm.setupTLSRelocationsFunction(); |
| 3331 | 3334 | try wasm.initializeTLSFunction(); |
| 3335 | try wasm.setupStartSection(); |
| 3332 | 3336 | try wasm.setupExports(); |
| 3333 | 3337 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| 3334 | 3338 | |
| ... | ... | @@ -3466,6 +3470,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3466 | 3470 | try wasm.setupInitMemoryFunction(); |
| 3467 | 3471 | try wasm.setupTLSRelocationsFunction(); |
| 3468 | 3472 | try wasm.initializeTLSFunction(); |
| 3473 | try wasm.setupStartSection(); |
| 3469 | 3474 | try wasm.setupExports(); |
| 3470 | 3475 | try wasm.writeToFile(enabled_features, emit_features_count, arena); |
| 3471 | 3476 | } |
| ... | ... | @@ -3657,6 +3662,17 @@ fn writeToFile( |
| 3657 | 3662 | section_count += 1; |
| 3658 | 3663 | } |
| 3659 | 3664 | |
| 3665 | if (wasm.entry) |entry_index| { |
| 3666 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 3667 | try writeVecSectionHeader( |
| 3668 | binary_bytes.items, |
| 3669 | header_offset, |
| 3670 | .start, |
| 3671 | @intCast(binary_bytes.items.len - header_offset - header_size), |
| 3672 | entry_index, |
| 3673 | ); |
| 3674 | } |
| 3675 | |
| 3660 | 3676 | // element section (function table) |
| 3661 | 3677 | if (wasm.function_table.count() > 0) { |
| 3662 | 3678 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| ... | ... | @@ -3690,7 +3706,7 @@ fn writeToFile( |
| 3690 | 3706 | } |
| 3691 | 3707 | |
| 3692 | 3708 | // When the shared-memory option is enabled, we *must* emit the 'data count' section. |
| 3693 | | const data_segments_count = wasm.data_segments.count() - @intFromBool(wasm.data_segments.contains(".bss") and import_memory); |
| 3709 | const data_segments_count = wasm.data_segments.count() - @intFromBool(wasm.data_segments.contains(".bss") and !import_memory); |
| 3694 | 3710 | if (data_segments_count != 0 and wasm.base.options.shared_memory) { |
| 3695 | 3711 | const header_offset = try reserveVecSectionHeader(&binary_bytes); |
| 3696 | 3712 | try writeVecSectionHeader( |