authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-08 12:05:32+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-08-11 20:00:12+02:00
loge02750fc0bde5c37a14e0173804987030be0078d
treec78d1477b082972eec3d76c99bd28ac589ad709b
parentcce0b43270a57a884e7d7aeba25bc6953741156e

wasm: add __global_base/__wasm_first_page_end handling + init_funcs fix


2 files changed, 96 insertions(+), 88 deletions(-)

src/link/Wasm.zig+59-51
......@@ -1778,14 +1778,16 @@ pub const ObjectDataImport = extern struct {
17781778 __zig_error_name_table,
17791779 __zig_tag_names,
17801780 __zig_tag_name_table,
1781 __global_base,
17811782 __heap_base,
17821783 __heap_end,
1784 __wasm_first_page_end,
17831785 /// Next, an `ObjectData.Index`.
17841786 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
17851787 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
17861788 _,
17871789
1788 const first_object = @backingInt(Resolution.__heap_end) + 1;
1790 const first_object = @backingInt(Resolution.__wasm_first_page_end) + 1;
17891791
17901792 pub const Unpacked = union(enum) {
17911793 unresolved,
......@@ -1793,8 +1795,10 @@ pub const ObjectDataImport = extern struct {
17931795 __zig_error_name_table,
17941796 __zig_tag_names,
17951797 __zig_tag_name_table,
1798 __global_base,
17961799 __heap_base,
17971800 __heap_end,
1801 __wasm_first_page_end,
17981802 object: ObjectData.Index,
17991803 uav_exe: UavsExeIndex,
18001804 uav_obj: UavsObjIndex,
......@@ -1809,8 +1813,10 @@ pub const ObjectDataImport = extern struct {
18091813 .__zig_error_name_table => .__zig_error_name_table,
18101814 .__zig_tag_names => .__zig_tag_names,
18111815 .__zig_tag_name_table => .__zig_tag_name_table,
1816 .__global_base => .__global_base,
18121817 .__heap_base => .__heap_base,
18131818 .__heap_end => .__heap_end,
1819 .__wasm_first_page_end => .__wasm_first_page_end,
18141820 _ => {
18151821 const object_index = @backingInt(r) - first_object;
18161822
......@@ -1847,8 +1853,10 @@ pub const ObjectDataImport = extern struct {
18471853 .__zig_error_name_table => .__zig_error_name_table,
18481854 .__zig_tag_names => .__zig_tag_names,
18491855 .__zig_tag_name_table => .__zig_tag_name_table,
1856 .__global_base => .__global_base,
18501857 .__heap_base => .__heap_base,
18511858 .__heap_end => .__heap_end,
1859 .__wasm_first_page_end => .__wasm_first_page_end,
18521860 .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))),
18531861 inline .uav_exe, .uav_obj => |i| @fromBackingInt(@intCast(first_object + wasm.object_datas.items.len + @backingInt(i))),
18541862 .nav_exe => |i| @fromBackingInt(@intCast(first_object + wasm.object_datas.items.len + wasm.uavs_exe.entries.len + @backingInt(i))),
......@@ -1886,8 +1894,10 @@ pub const ObjectDataImport = extern struct {
18861894 .__zig_error_name_table,
18871895 .__zig_tag_names,
18881896 .__zig_tag_name_table,
1897 .__global_base,
18891898 .__heap_base,
18901899 .__heap_end,
1900 .__wasm_first_page_end,
18911901 .uav_exe,
18921902 .uav_obj,
18931903 .nav_exe,
......@@ -1910,8 +1920,11 @@ pub const ObjectDataImport = extern struct {
19101920 .__zig_error_name_table => .{ .segment = .__zig_error_name_table, .offset = 0 },
19111921 .__zig_tag_names => .{ .segment = .__zig_tag_names, .offset = 0 },
19121922 .__zig_tag_name_table => .{ .segment = .__zig_tag_name_table, .offset = 0 },
1913 .__heap_base => .{ .segment = .__heap_base, .offset = 0 },
1914 .__heap_end => .{ .segment = .__heap_end, .offset = 0 },
1923 .__global_base,
1924 .__heap_base,
1925 .__heap_end,
1926 .__wasm_first_page_end,
1927 => unreachable,
19151928 .uav_exe => |i| .{ .segment = .pack(wasm, .{ .uav_exe = i }), .offset = 0 },
19161929 .uav_obj => |i| .{ .segment = .pack(wasm, .{ .uav_obj = i }), .offset = 0 },
19171930 .nav_exe => |i| .{ .segment = .pack(wasm, .{ .nav_exe = i }), .offset = 0 },
......@@ -1927,8 +1940,10 @@ pub const ObjectDataImport = extern struct {
19271940 .__zig_tag_names,
19281941 .__zig_tag_name_table,
19291942 => .{ .binding = .local },
1943 .__global_base,
19301944 .__heap_base,
19311945 .__heap_end,
1946 .__wasm_first_page_end,
19321947 => unreachable,
19331948 .object => |i| i.ptr(wasm).flags,
19341949 inline .nav_exe, .nav_obj => |i| {
......@@ -1976,8 +1991,10 @@ pub const ObjectDataImport = extern struct {
19761991 .__zig_error_name_table => @tagName(.__zig_error_name_table),
19771992 .__zig_tag_names => @tagName(.__zig_tag_names),
19781993 .__zig_tag_name_table => @tagName(.__zig_tag_name_table),
1994 .__global_base => @tagName(.__global_base),
19791995 .__heap_base => @tagName(.__heap_base),
19801996 .__heap_end => @tagName(.__heap_end),
1997 .__wasm_first_page_end => @tagName(.__wasm_first_page_end),
19811998 inline .uav_exe, .uav_obj => |i| std.fmt.bufPrint(
19821999 buf,
19832000 "__anon_{d}",
......@@ -2006,7 +2023,7 @@ pub const ObjectDataImport = extern struct {
20062023 const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu);
20072024 return @intCast(table_len * elem_size);
20082025 },
2009 .__heap_base, .__heap_end => wasm.pointerSize(),
2026 .__global_base, .__heap_base, .__heap_end, .__wasm_first_page_end => 0,
20102027 .object => |i| i.ptr(wasm).size,
20112028 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
20122029 };
......@@ -2056,17 +2073,12 @@ pub const DataSegmentId = enum(u32) {
20562073 __zig_tag_names,
20572074 /// All tag name slices for all `@tagName` implementations, concatenated together.
20582075 __zig_tag_name_table,
2059 /// This and `__heap_end` are better retrieved via a global, but there is
2060 /// some suboptimal code out there (wasi libc) that additionally needs them
2061 /// as data symbols.
2062 __heap_base,
2063 __heap_end,
20642076 /// First, an `ObjectDataSegment.Index`.
20652077 /// Next, index into `uavs_obj` or `uavs_exe` depending on whether emitting an object.
20662078 /// Next, index into `navs_obj` or `navs_exe` depending on whether emitting an object.
20672079 _,
20682080
2069 const first_object = @backingInt(DataSegmentId.__heap_end) + 1;
2081 const first_object = @backingInt(DataSegmentId.__zig_tag_name_table) + 1;
20702082
20712083 pub const Category = enum {
20722084 /// Thread-local variables.
......@@ -2083,8 +2095,6 @@ pub const DataSegmentId = enum(u32) {
20832095 __zig_error_name_table,
20842096 __zig_tag_names,
20852097 __zig_tag_name_table,
2086 __heap_base,
2087 __heap_end,
20882098 object: ObjectDataSegment.Index,
20892099 uav_exe: UavsExeIndex,
20902100 uav_obj: UavsObjIndex,
......@@ -2098,8 +2108,6 @@ pub const DataSegmentId = enum(u32) {
20982108 .__zig_error_name_table => .__zig_error_name_table,
20992109 .__zig_tag_names => .__zig_tag_names,
21002110 .__zig_tag_name_table => .__zig_tag_name_table,
2101 .__heap_base => .__heap_base,
2102 .__heap_end => .__heap_end,
21032111 .object => |i| @fromBackingInt(@intCast(first_object + @backingInt(i))),
21042112 inline .uav_exe, .uav_obj => |i| @fromBackingInt(@intCast(first_object + wasm.object_data_segments.items.len + @backingInt(i))),
21052113 .nav_exe => |i| @fromBackingInt(@intCast(first_object + wasm.object_data_segments.items.len + wasm.uavs_exe.entries.len + @backingInt(i))),
......@@ -2113,8 +2121,6 @@ pub const DataSegmentId = enum(u32) {
21132121 .__zig_error_name_table => .__zig_error_name_table,
21142122 .__zig_tag_names => .__zig_tag_names,
21152123 .__zig_tag_name_table => .__zig_tag_name_table,
2116 .__heap_base => .__heap_base,
2117 .__heap_end => .__heap_end,
21182124 _ => {
21192125 const object_index = @backingInt(id) - first_object;
21202126
......@@ -2164,8 +2170,6 @@ pub const DataSegmentId = enum(u32) {
21642170 .__zig_error_name_table,
21652171 .__zig_tag_names,
21662172 .__zig_tag_name_table,
2167 .__heap_base,
2168 .__heap_end,
21692173 => .data,
21702174
21712175 .object => |i| {
......@@ -2192,8 +2196,6 @@ pub const DataSegmentId = enum(u32) {
21922196 .__zig_error_name_table,
21932197 .__zig_tag_names,
21942198 .__zig_tag_name_table,
2195 .__heap_base,
2196 .__heap_end,
21972199 => false,
21982200
21992201 .object => |i| i.ptr(wasm).flags.tls,
......@@ -2213,8 +2215,6 @@ pub const DataSegmentId = enum(u32) {
22132215
22142216 .__zig_error_name_table,
22152217 .__zig_tag_name_table,
2216 .__heap_base,
2217 .__heap_end,
22182218 => false,
22192219
22202220 .object => |i| i.ptr(wasm).flags.strings,
......@@ -2229,8 +2229,6 @@ pub const DataSegmentId = enum(u32) {
22292229 .__zig_error_name_table,
22302230 .__zig_tag_names,
22312231 .__zig_tag_name_table,
2232 .__heap_base,
2233 .__heap_end,
22342232 => false,
22352233
22362234 .object => |i| i.ptr(wasm).flags.retain,
......@@ -2251,8 +2249,6 @@ pub const DataSegmentId = enum(u32) {
22512249 .__zig_tag_name_table,
22522250 .uav_exe,
22532251 .uav_obj,
2254 .__heap_base,
2255 .__heap_end,
22562252 => ".data",
22572253
22582254 .object => |i| i.ptr(wasm).name.unwrap().?.slice(wasm),
......@@ -2272,7 +2268,7 @@ pub const DataSegmentId = enum(u32) {
22722268 pub fn alignment(id: DataSegmentId, wasm: *const Wasm) Alignment {
22732269 return switch (unpack(id, wasm)) {
22742270 .__zig_error_names, .__zig_tag_names => .@"1",
2275 .__zig_error_name_table, .__zig_tag_name_table, .__heap_base, .__heap_end => wasm.pointerAlignment(),
2271 .__zig_error_name_table, .__zig_tag_name_table => wasm.pointerAlignment(),
22762272 .object => |i| i.ptr(wasm).flags.alignment,
22772273 inline .uav_exe, .uav_obj => |i| {
22782274 const zcu = wasm.base.comp.zcu.?;
......@@ -2304,7 +2300,7 @@ pub const DataSegmentId = enum(u32) {
23042300 .__zig_error_name_table => wasm.error_name_table_ref_count,
23052301 .__zig_tag_names => @intCast(wasm.tag_name_offs.items.len),
23062302 .__zig_tag_name_table => wasm.tag_name_table_ref_count,
2307 .object, .uav_obj, .nav_obj, .__heap_base, .__heap_end => 0,
2303 .object, .uav_obj, .nav_obj => 0,
23082304 inline .uav_exe, .nav_exe => |i| i.value(wasm).count,
23092305 };
23102306 }
......@@ -2317,8 +2313,6 @@ pub const DataSegmentId = enum(u32) {
23172313 .__zig_error_name_table,
23182314 .__zig_tag_names,
23192315 .__zig_tag_name_table,
2320 .__heap_base,
2321 .__heap_end,
23222316 => false,
23232317
23242318 .object => |i| i.ptr(wasm).flags.is_passive,
......@@ -2332,8 +2326,6 @@ pub const DataSegmentId = enum(u32) {
23322326 .__zig_error_name_table,
23332327 .__zig_tag_names,
23342328 .__zig_tag_name_table,
2335 .__heap_base,
2336 .__heap_end,
23372329 => false,
23382330
23392331 .object => |i| i.ptr(wasm).payload.off == .none,
......@@ -2359,7 +2351,6 @@ pub const DataSegmentId = enum(u32) {
23592351 const elem_size = Zcu.Type.slice_const_u8_sentinel_0.abiSize(zcu);
23602352 return @intCast(table_len * elem_size);
23612353 },
2362 .__heap_base, .__heap_end => wasm.pointerSize(),
23632354 .object => |i| i.ptr(wasm).payload.len,
23642355 inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code.len,
23652356 };
......@@ -2491,6 +2482,7 @@ pub const Func = extern struct {
24912482/// Type reflection is used on the field names to autopopulate each field
24922483/// during initialization.
24932484const PreloadedStrings = struct {
2485 __global_base: String,
24942486 __heap_base: String,
24952487 __heap_end: String,
24962488 __indirect_function_table: String,
......@@ -2504,6 +2496,7 @@ const PreloadedStrings = struct {
25042496 __wasm_init_memory: String,
25052497 __wasm_init_memory_flag: String,
25062498 __wasm_init_tls: String,
2499 __wasm_first_page_end: String,
25072500 __zig_error_names: String,
25082501 __zig_error_name_table: String,
25092502 __zig_errors_len: String,
......@@ -3907,21 +3900,11 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
39073900 try markFunctionImport(wasm, name, import, @fromBackingInt(@intCast(i)));
39083901 }
39093902 }
3910 // Also treat init functions as roots.
3911 for (wasm.object_init_funcs.items) |init_func| {
3912 const func = init_func.function_index.ptr(wasm);
3913 if (func.object_index.ptr(wasm).is_included) {
3914 try markFunction(wasm, init_func.function_index, false);
3915 }
3916 }
3917 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
3918
39193903 for (wasm.object_global_imports.keys(), wasm.object_global_imports.values(), 0..) |name, *import, i| {
39203904 if (import.flags.isIncluded(rdynamic, is_obj)) {
39213905 try markGlobalImport(wasm, name, import, @fromBackingInt(@intCast(i)));
39223906 }
39233907 }
3924 wasm.globals_end_prelink = @intCast(wasm.globals.entries.len);
39253908 wasm.global_exports_len = @intCast(wasm.global_exports.items.len);
39263909
39273910 for (wasm.object_table_imports.keys(), wasm.object_table_imports.values(), 0..) |name, *import, i| {
......@@ -3944,6 +3927,8 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
39443927 wasm.memories.limits.flags.has_max = wasm.memories.limits.flags.has_max or memory_import.limits_has_max;
39453928 }
39463929
3930 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
3931 wasm.globals_end_prelink = @intCast(wasm.globals.entries.len);
39473932 wasm.function_imports_len_prelink = @intCast(wasm.function_imports.entries.len);
39483933 wasm.data_imports_len_prelink = @intCast(wasm.data_imports.entries.len);
39493934}
......@@ -3998,7 +3983,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link
39983983 const rdynamic = comp.config.rdynamic;
39993984 const is_obj = comp.config.output_mode == .Obj;
40003985 const function = i.ptr(wasm);
4001 markObject(wasm, function.object_index);
3986 try markObject(wasm, function.object_index);
40023987
40033988 if (!is_obj and (override_export or function.flags.isExported(rdynamic))) {
40043989 const symbol_name = function.name.unwrap().?;
......@@ -4012,8 +3997,15 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link
40123997 try wasm.markRelocations(function.relocations(wasm));
40133998}
40143999
4015fn markObject(wasm: *Wasm, i: ObjectIndex) void {
4016 i.ptr(wasm).is_included = true;
4000fn markObject(wasm: *Wasm, i: ObjectIndex) link.Error!void {
4001 const object = i.ptr(wasm);
4002 if (object.is_included) return;
4003 object.is_included = true;
4004
4005 const init_funcs = wasm.object_init_funcs.items[object.init_funcs.off..][0..object.init_funcs.len];
4006 for (init_funcs) |init_func| {
4007 try markFunction(wasm, init_func.function_index, false);
4008 }
40174009}
40184010
40194011/// Recursively mark alive everything referenced by the global.
......@@ -4076,6 +4068,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err
40764068 const rdynamic = comp.config.rdynamic;
40774069 const is_obj = comp.config.output_mode == .Obj;
40784070 const global = i.ptr(wasm);
4071 try markObject(wasm, global.object_index);
40794072
40804073 if (!is_obj and (override_export or global.flags.isExported(rdynamic))) try wasm.global_exports.append(gpa, .{
40814074 .name = global.name.unwrap().?,
......@@ -4122,6 +4115,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.Err
41224115 const segment = segment_index.ptr(wasm);
41234116 if (segment.flags.alive) return;
41244117 segment.flags.alive = true;
4118 try markObject(wasm, segment.object_index);
41254119
41264120 wasm.any_passive_inits = wasm.any_passive_inits or segment.flags.is_passive or
41274121 (comp.config.import_memory and !wasm.isBss(segment.name));
......@@ -4143,16 +4137,16 @@ pub fn markDataImport(
41434137 const gpa = comp.gpa;
41444138 const is_obj = comp.config.output_mode == .Obj;
41454139
4146 try wasm.data_segments.ensureUnusedCapacity(gpa, 1);
4147
41484140 if (import.resolution == .unresolved) {
41494141 if (!is_obj) {
4150 if (name == wasm.preloaded_strings.__heap_base) {
4142 if (name == wasm.preloaded_strings.__global_base) {
4143 import.resolution = .__global_base;
4144 } else if (name == wasm.preloaded_strings.__heap_base) {
41514145 import.resolution = .__heap_base;
4152 wasm.data_segments.putAssumeCapacity(.__heap_base, {});
41534146 } else if (name == wasm.preloaded_strings.__heap_end) {
41544147 import.resolution = .__heap_end;
4155 wasm.data_segments.putAssumeCapacity(.__heap_end, {});
4148 } else if (name == wasm.preloaded_strings.__wasm_first_page_end) {
4149 import.resolution = .__wasm_first_page_end;
41564150 } else {
41574151 try wasm.data_imports.put(gpa, name, .fromObject(data_index, wasm));
41584152 }
......@@ -4857,6 +4851,17 @@ pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 {
48574851 return wasm.flush_buffer.data_segments.get(ds_id).?;
48584852}
48594853
4854pub fn syntheticDataAddr(wasm: *const Wasm, resolution: ObjectDataImport.Resolution) ?u32 {
4855 const virtual_addrs = wasm.flush_buffer.virtual_addrs;
4856 return switch (resolution.unpack(wasm)) {
4857 .__global_base => virtual_addrs.global_base,
4858 .__heap_base => virtual_addrs.heap_base,
4859 .__heap_end => virtual_addrs.heap_end,
4860 .__wasm_first_page_end => virtual_addrs.wasm_first_page_end,
4861 else => null,
4862 };
4863}
4864
48604865/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
48614866pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
48624867 assert(wasm.flush_buffer.memory_layout_finished);
......@@ -4881,8 +4886,11 @@ pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
48814886 const segment_base_addr = wasm.flush_buffer.data_segments.get(ds_id).?;
48824887 return segment_base_addr + object_data.offset;
48834888 },
4889 .__global_base,
48844890 .__heap_base,
48854891 .__heap_end,
4892 .__wasm_first_page_end,
4893 => return wasm.syntheticDataAddr(import.resolution).?,
48864894 .uav_exe,
48874895 .nav_exe,
48884896 => {
src/link/Wasm/Flush.zig+37-37
......@@ -41,6 +41,7 @@ data_imports: std.array_hash_map.Auto(String, Wasm.DataImportId) = .empty,
4141data_exports: std.array_hash_map.Auto(String, DataExportSymbol) = .empty,
4242
4343indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void) = .empty,
44sorted_init_funcs: std.ArrayList(Wasm.InitFunc) = .empty,
4445
4546/// A subset of the full interned function type list created only during flush.
4647func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty,
......@@ -53,6 +54,8 @@ data_relocs: std.ArrayList(Relocation) = .empty,
5354/// For debug purposes only.
5455memory_layout_finished: bool = false,
5556
57virtual_addrs: VirtualAddrs = undefined,
58
5659/// Index into `func_types`.
5760pub const FuncTypeIndex = enum(u32) {
5861 _,
......@@ -201,11 +204,13 @@ pub fn clear(f: *Flush) void {
201204 f.function_export_symbols.clearRetainingCapacity();
202205 f.data_exports.clearRetainingCapacity();
203206 f.indirect_function_table.clearRetainingCapacity();
207 f.sorted_init_funcs.clearRetainingCapacity();
204208 f.func_types.clearRetainingCapacity();
205209 f.enum_tag_name_table.clearRetainingCapacity();
206210 f.code_relocs.clearRetainingCapacity();
207211 f.data_relocs.clearRetainingCapacity();
208212 f.memory_layout_finished = false;
213 f.virtual_addrs = undefined;
209214}
210215
211216pub fn deinit(f: *Flush, gpa: Allocator) void {
......@@ -220,6 +225,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
220225 f.data_imports.deinit(gpa);
221226 f.data_exports.deinit(gpa);
222227 f.indirect_function_table.deinit(gpa);
228 f.sorted_init_funcs.deinit(gpa);
223229 f.func_types.deinit(gpa);
224230 f.enum_tag_name_table.deinit(gpa);
225231 f.code_relocs.deinit(gpa);
......@@ -542,9 +548,15 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
542548 for (wasm.object_indirect_function_set.keys()) |object_function_index|
543549 f.indirect_function_table.putAssumeCapacity(.fromObjectFunction(wasm, object_function_index), {});
544550
545 if (wasm.object_init_funcs.items.len > 0) {
551 try f.sorted_init_funcs.ensureUnusedCapacity(gpa, wasm.object_init_funcs.items.len);
552 for (wasm.object_init_funcs.items) |init_func| {
553 const func = init_func.function_index.ptr(wasm);
554 if (!func.object_index.ptr(wasm).is_included) continue;
555 f.sorted_init_funcs.appendAssumeCapacity(init_func);
556 }
557 if (f.sorted_init_funcs.items.len > 0) {
546558 // Zig has no constructors so these are only for object file inputs.
547 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);
559 mem.sortUnstable(Wasm.InitFunc, f.sorted_init_funcs.items, {}, Wasm.InitFunc.lessThan);
548560 if (!is_obj) try wasm.functions.put(gpa, .__wasm_call_ctors, {});
549561 }
550562
......@@ -703,10 +715,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
703715 // Always place the stack at the start by default unless the user specified the global-base flag.
704716 const place_stack_first, var memory_ptr: u64 = if (wasm.global_base) |base| .{ false, base } else .{ true, 0 };
705717
706 var virtual_addrs: VirtualAddrs = .{
718 const virtual_addrs = &f.virtual_addrs;
719 virtual_addrs.* = .{
720 .global_base = undefined,
707721 .stack_pointer = undefined,
708722 .heap_base = undefined,
709723 .heap_end = undefined,
724 .wasm_first_page_end = page_size,
710725 .tls_base = null,
711726 .tls_align = .none,
712727 .tls_size = null,
......@@ -719,10 +734,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
719734 virtual_addrs.stack_pointer = @intCast(memory_ptr);
720735 }
721736
737 const data_vaddr: u32 = @intCast(memory_ptr);
738 virtual_addrs.global_base = data_vaddr;
739
722740 const segment_ids = f.data_segments.keys();
723741 const segment_vaddrs = f.data_segments.values();
724742 assert(f.data_segment_groups.items.len == 0);
725 const data_vaddr: u32 = @intCast(memory_ptr);
726743 if (segment_ids.len > 0) {
727744 var seen_tls: enum { before, during, after } = .before;
728745 var category: Wasm.DataSegmentId.Category = undefined;
......@@ -1165,7 +1182,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
11651182 .__wasm_init_memory => {
11661183 const code_start = try reserveSize(gpa, binary_bytes);
11671184 defer replaceSize(binary_bytes, code_start);
1168 try emitInitMemoryFunction(wasm, binary_bytes, &virtual_addrs);
1185 try emitInitMemoryFunction(wasm, binary_bytes);
11691186 },
11701187 .__wasm_init_tls => {
11711188 const code_start = try reserveSize(gpa, binary_bytes);
......@@ -1327,14 +1344,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
13271344 const output_offset: u32 = @intCast(binary_bytes.items.len - section_offset);
13281345 append: {
13291346 const code = switch (segment_id.unpack(wasm)) {
1330 .__heap_base => {
1331 mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_base, .little);
1332 break :append;
1333 },
1334 .__heap_end => {
1335 mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_end, .little);
1336 break :append;
1337 },
13381347 .__zig_error_names => {
13391348 try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items);
13401349 break :append;
......@@ -1643,22 +1652,9 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
16431652 const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
16441653 defer replaceHeader(binary_bytes, sub_offset, @backingInt(Object.SubsectionType.init_funcs));
16451654
1646 const init_funcs = wasm.object_init_funcs.items;
1647 const total_functions: u32 = b: {
1648 var cnt: u32 = 0;
1649 for (init_funcs) |init_func| {
1650 const func = init_func.function_index.ptr(wasm);
1651 if (!func.object_index.ptr(wasm).is_included) continue;
1652 cnt += 1;
1653 }
1654 break :b cnt;
1655 };
1656 try appendLeb128(gpa, binary_bytes, total_functions);
1657
1658 for (init_funcs) |init_func| {
1659 const func = init_func.function_index.ptr(wasm);
1660 if (!func.object_index.ptr(wasm).is_included) continue;
1655 try appendLeb128(gpa, binary_bytes, @as(u32, @intCast(f.sorted_init_funcs.items.len)));
16611656
1657 for (f.sorted_init_funcs.items) |init_func| {
16621658 try appendLeb128(gpa, binary_bytes, init_func.priority);
16631659 const out_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index);
16641660 const symbol_index: u32 = symbol_table_offsets.function + @backingInt(out_index);
......@@ -1736,9 +1732,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
17361732}
17371733
17381734const VirtualAddrs = struct {
1735 global_base: u32,
17391736 stack_pointer: u32,
17401737 heap_base: u32,
17411738 heap_end: u32,
1739 wasm_first_page_end: u32,
17421740 tls_base: ?u32,
17431741 tls_align: Alignment,
17441742 tls_size: ?u32,
......@@ -2587,6 +2585,9 @@ const RelocAddr = struct {
25872585 const flush = &wasm.flush_buffer;
25882586 if (wasm.object_data_imports.getPtr(name)) |import| {
25892587 if (import.resolution != .unresolved) {
2588 if (wasm.syntheticDataAddr(import.resolution)) |addr| {
2589 return fromAddr(addr, addend);
2590 }
25902591 return fromDataLoc(flush, import.resolution.dataLoc(wasm), addend);
25912592 }
25922593 }
......@@ -2600,8 +2601,11 @@ const RelocAddr = struct {
26002601 }
26012602
26022603 fn fromDataLoc(flush: *const Flush, data_loc: Wasm.DataLoc, addend: i32) RelocAddr {
2603 const base_addr: i64 = flush.data_segments.get(data_loc.segment).?;
2604 return .{ .addr = @intCast(base_addr + data_loc.offset + addend) };
2604 return fromAddr(flush.data_segments.get(data_loc.segment).? + data_loc.offset, addend);
2605 }
2606
2607 fn fromAddr(addr: u32, addend: i32) RelocAddr {
2608 return .{ .addr = @intCast(@as(i64, addr) + addend) };
26052609 }
26062610};
26072611
......@@ -2643,9 +2647,8 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *ArrayList(u8)) Alloca
26432647 try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1);
26442648 appendReservedUleb32(binary_bytes, 0); // no locals
26452649
2646 for (wasm.object_init_funcs.items) |init_func| {
2650 for (wasm.flush_buffer.sorted_init_funcs.items) |init_func| {
26472651 const func = init_func.function_index.ptr(wasm);
2648 if (!func.object_index.ptr(wasm).is_included) continue;
26492652 const ty = func.type_index.ptr(wasm);
26502653 const n_returns = ty.returns.slice(wasm).len;
26512654
......@@ -2662,14 +2665,11 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *ArrayList(u8)) Alloca
26622665 binary_bytes.appendAssumeCapacity(@backingInt(std.wasm.Opcode.end)); // end function body
26632666}
26642667
2665fn emitInitMemoryFunction(
2666 wasm: *const Wasm,
2667 binary_bytes: *ArrayList(u8),
2668 virtual_addrs: *const VirtualAddrs,
2669) Allocator.Error!void {
2668fn emitInitMemoryFunction(wasm: *const Wasm, binary_bytes: *ArrayList(u8)) Allocator.Error!void {
26702669 const comp = wasm.base.comp;
26712670 const gpa = comp.gpa;
26722671 const shared_memory = comp.config.shared_memory;
2672 const virtual_addrs = &wasm.flush_buffer.virtual_addrs;
26732673
26742674 // Passive segments are used to avoid memory being reinitialized on each
26752675 // thread's instantiation. These passive segments are initialized and