authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-09 20:55:39-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log788b7f8f115e8510176ca7fbfdc04fb48d69ecb1
tree91208c95559c3d9ddb00ea97c6a7a64ca70292c2
parent1c4b4fb51604f388bb4355e566aac4ea9fda8960

wasm linker: don't call init functions unless object included


3 files changed, 14 insertions(+), 5 deletions(-)

src/link/Wasm.zig+10-2
...@@ -117,7 +117,7 @@ object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty,...@@ -117,7 +117,7 @@ object_memories: std.ArrayListUnmanaged(ObjectMemory) = .empty,
117object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,117object_relocations: std.MultiArrayList(ObjectRelocation) = .empty,
118118
119/// List of initialization functions. These must be called in order of priority119/// List of initialization functions. These must be called in order of priority
120/// by the (synthetic) __wasm_call_ctors function.120/// by the (synthetic) `__wasm_call_ctors` function.
121object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,121object_init_funcs: std.ArrayListUnmanaged(InitFunc) = .empty,
122122
123/// The data section of an object has many segments. Each segment corresponds123/// The data section of an object has many segments. Each segment corresponds
...@@ -3308,7 +3308,10 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v...@@ -3308,7 +3308,10 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!v
3308 }3308 }
3309 // Also treat init functions as roots.3309 // Also treat init functions as roots.
3310 for (wasm.object_init_funcs.items) |init_func| {3310 for (wasm.object_init_funcs.items) |init_func| {
3311 try markFunction(wasm, init_func.function_index);3311 const func = init_func.function_index.ptr(wasm);
3312 if (func.object_index.ptr(wasm).is_included) {
3313 try markFunction(wasm, init_func.function_index);
3314 }
3312 }3315 }
3313 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);3316 wasm.functions_end_prelink = @intCast(wasm.functions.entries.len);
3314 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);3317 wasm.function_exports_len = @intCast(wasm.function_exports.items.len);
...@@ -3383,6 +3386,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {...@@ -3383,6 +3386,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {
3383 const rdynamic = comp.config.rdynamic;3386 const rdynamic = comp.config.rdynamic;
3384 const is_obj = comp.config.output_mode == .Obj;3387 const is_obj = comp.config.output_mode == .Obj;
3385 const function = i.ptr(wasm);3388 const function = i.ptr(wasm);
3389 markObject(wasm, function.object_index);
33863390
3387 if (!is_obj and function.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{3391 if (!is_obj and function.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
3388 .name = function.name.unwrap().?,3392 .name = function.name.unwrap().?,
...@@ -3392,6 +3396,10 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {...@@ -3392,6 +3396,10 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex) link.File.FlushError!void {
3392 try wasm.markRelocations(function.relocations(wasm));3396 try wasm.markRelocations(function.relocations(wasm));
3393}3397}
33943398
3399fn markObject(wasm: *Wasm, i: ObjectIndex) void {
3400 i.ptr(wasm).is_included = true;
3401}
3402
3395/// Recursively mark alive everything referenced by the global.3403/// Recursively mark alive everything referenced by the global.
3396fn markGlobalImport(3404fn markGlobalImport(
3397 wasm: *Wasm,3405 wasm: *Wasm,
src/link/Wasm/Flush.zig+2-3
...@@ -188,8 +188,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -188,8 +188,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
188 for (wasm.object_indirect_function_set.keys()) |object_function_index|188 for (wasm.object_indirect_function_set.keys()) |object_function_index|
189 f.indirect_function_table.putAssumeCapacity(.fromObjectFunction(wasm, object_function_index), {});189 f.indirect_function_table.putAssumeCapacity(.fromObjectFunction(wasm, object_function_index), {});
190190
191 // TODO only include init functions for objects with must_link=true or
192 // which have any alive functions inside them.
193 if (wasm.object_init_funcs.items.len > 0) {191 if (wasm.object_init_funcs.items.len > 0) {
194 // Zig has no constructors so these are only for object file inputs.192 // Zig has no constructors so these are only for object file inputs.
195 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);193 mem.sortUnstable(Wasm.InitFunc, wasm.object_init_funcs.items, {}, Wasm.InitFunc.lessThan);
...@@ -692,7 +690,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -692,7 +690,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
692 }690 }
693691
694 // When the shared-memory option is enabled, we *must* emit the 'data count' section.692 // When the shared-memory option is enabled, we *must* emit the 'data count' section.
695 if (f.data_segment_groups.items.len > 0 and shared_memory) {693 {
696 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);694 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
697 replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));695 replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len));
698 }696 }
...@@ -1644,6 +1642,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage...@@ -1644,6 +1642,7 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage
16441642
1645 for (wasm.object_init_funcs.items) |init_func| {1643 for (wasm.object_init_funcs.items) |init_func| {
1646 const func = init_func.function_index.ptr(wasm);1644 const func = init_func.function_index.ptr(wasm);
1645 if (!func.object_index.ptr(wasm).is_included) continue;
1647 const ty = func.type_index.ptr(wasm);1646 const ty = func.type_index.ptr(wasm);
1648 const n_returns = ty.returns.slice(wasm).len;1647 const n_returns = ty.returns.slice(wasm).len;
16491648
src/link/Wasm/Object.zig+2
...@@ -48,6 +48,7 @@ code_section_index: ?Wasm.ObjectSectionIndex,...@@ -48,6 +48,7 @@ code_section_index: ?Wasm.ObjectSectionIndex,
48global_section_index: ?Wasm.ObjectSectionIndex,48global_section_index: ?Wasm.ObjectSectionIndex,
49/// Guaranteed to be non-null when data segments has nonzero length.49/// Guaranteed to be non-null when data segments has nonzero length.
50data_section_index: ?Wasm.ObjectSectionIndex,50data_section_index: ?Wasm.ObjectSectionIndex,
51is_included: bool,
5152
52pub const RelativeSlice = struct {53pub const RelativeSlice = struct {
53 off: u32,54 off: u32,
...@@ -1414,6 +1415,7 @@ pub fn parse(...@@ -1414,6 +1415,7 @@ pub fn parse(
1414 .code_section_index = code_section_index,1415 .code_section_index = code_section_index,
1415 .global_section_index = global_section_index,1416 .global_section_index = global_section_index,
1416 .data_section_index = data_section_index,1417 .data_section_index = data_section_index,
1418 .is_included = must_link,
1417 };1419 };
1418}1420}
14191421