authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-14 19:58:52+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-28 15:47:07+01:00
logc986c6c90a5746cb671177e486a77bd78a5946b0
treefe0f223b4b9fae0af5c1ce446a7f88273c3b5695
parent589aef153709a3c1e0b1ee8af4bb4d710d46b792
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: do not merge unreferenced symbols

When a symbol is unreferenced and therefore garbage-collected, we do not merge its specific section into the final binary.

1 files changed, 47 insertions(+), 18 deletions(-)

src/link/Wasm.zig+47-18
...@@ -1981,10 +1981,16 @@ pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {...@@ -1981,10 +1981,16 @@ pub fn addTableFunction(wasm: *Wasm, symbol_index: u32) !void {
1981/// Starts at offset 1, where the value `0` represents an unresolved function pointer1981/// Starts at offset 1, where the value `0` represents an unresolved function pointer
1982/// or null-pointer1982/// or null-pointer
1983fn mapFunctionTable(wasm: *Wasm) void {1983fn mapFunctionTable(wasm: *Wasm) void {
1984 var it = wasm.function_table.valueIterator();1984 var it = wasm.function_table.iterator();
1985 var index: u32 = 1;1985 var index: u32 = 1;
1986 while (it.next()) |value_ptr| : (index += 1) {1986 while (it.next()) |entry| {
1987 value_ptr.* = index;1987 const symbol = entry.key_ptr.*.getSymbol(wasm);
1988 if (symbol.isAlive()) {
1989 entry.value_ptr.* = index;
1990 index += 1;
1991 } else {
1992 wasm.function_table.removeByPtr(entry.key_ptr);
1993 }
1988 }1994 }
19891995
1990 if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) {1996 if (wasm.base.options.import_table or wasm.base.options.output_mode == .Obj) {
...@@ -2242,14 +2248,23 @@ fn allocateAtoms(wasm: *Wasm) !void {...@@ -2242,14 +2248,23 @@ fn allocateAtoms(wasm: *Wasm) !void {
2242 while (true) {2248 while (true) {
2243 const atom = wasm.getAtomPtr(atom_index);2249 const atom = wasm.getAtomPtr(atom_index);
2244 const symbol_loc = atom.symbolLoc();2250 const symbol_loc = atom.symbolLoc();
2245 if (wasm.code_section_index) |index| {2251 const sym = symbol_loc.getSymbol(wasm);
2246 if (index == entry.key_ptr.*) {2252 if (sym.isDead()) {
2247 if (!wasm.resolved_symbols.contains(symbol_loc)) {2253 // Dead symbols must be unlinked from the linked-list to prevent them
2248 // only allocate resolved function body's.2254 // from being emit into the binary.
2249 atom_index = atom.prev orelse break;2255 if (atom.prev) |prev_index| {
2250 continue;2256 const prev = wasm.getAtomPtr(prev_index);
2251 }2257 prev.next = atom.next;
2252 }2258 }
2259 atom_index = atom.next orelse {
2260 atom.prev = null;
2261 break;
2262 };
2263 const next = wasm.getAtomPtr(atom_index);
2264 next.prev = atom.prev;
2265 atom.prev = null;
2266 atom.next = null;
2267 continue;
2253 }2268 }
2254 offset = @intCast(atom.alignment.forward(offset));2269 offset = @intCast(atom.alignment.forward(offset));
2255 atom.offset = offset;2270 atom.offset = offset;
...@@ -2358,11 +2373,17 @@ fn setupInitFunctions(wasm: *Wasm) !void {...@@ -2358,11 +2373,17 @@ fn setupInitFunctions(wasm: *Wasm) !void {
2358 .file = @as(u16, @intCast(file_index)),2373 .file = @as(u16, @intCast(file_index)),
2359 .priority = init_func.priority,2374 .priority = init_func.priority,
2360 });2375 });
2376 try wasm.mark(.{ .index = init_func.symbol_index, .file = @intCast(file_index) });
2361 }2377 }
2362 }2378 }
23632379
2364 // sort the initfunctions based on their priority2380 // sort the initfunctions based on their priority
2365 mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);2381 mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
2382
2383 if (wasm.init_funcs.items.len > 0) {
2384 const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
2385 try wasm.mark(loc);
2386 }
2366}2387}
23672388
2368/// Generates an atom containing the global error set' size.2389/// Generates an atom containing the global error set' size.
...@@ -2463,6 +2484,9 @@ fn createSyntheticFunction(...@@ -2463,6 +2484,9 @@ fn createSyntheticFunction(
2463 const loc = wasm.findGlobalSymbol(symbol_name) orelse2484 const loc = wasm.findGlobalSymbol(symbol_name) orelse
2464 try wasm.createSyntheticSymbol(symbol_name, .function);2485 try wasm.createSyntheticSymbol(symbol_name, .function);
2465 const symbol = loc.getSymbol(wasm);2486 const symbol = loc.getSymbol(wasm);
2487 if (symbol.isDead()) {
2488 return;
2489 }
2466 const ty_index = try wasm.putOrGetFuncType(func_ty);2490 const ty_index = try wasm.putOrGetFuncType(func_ty);
2467 // create function with above type2491 // create function with above type
2468 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));2492 const func_index = wasm.imported_functions_count + @as(u32, @intCast(wasm.functions.count()));
...@@ -2628,10 +2652,10 @@ fn setupImports(wasm: *Wasm) !void {...@@ -2628,10 +2652,10 @@ fn setupImports(wasm: *Wasm) !void {
2628 }2652 }
26292653
2630 const symbol = symbol_loc.getSymbol(wasm);2654 const symbol = symbol_loc.getSymbol(wasm);
2631 if (std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table")) {2655 if (symbol.isDead() or
2632 continue;2656 !symbol.requiresImport() or
2633 }2657 std.mem.eql(u8, symbol_loc.getName(wasm), "__indirect_function_table"))
2634 if (!symbol.requiresImport()) {2658 {
2635 continue;2659 continue;
2636 }2660 }
26372661
...@@ -2697,7 +2721,11 @@ fn mergeSections(wasm: *Wasm) !void {...@@ -2697,7 +2721,11 @@ fn mergeSections(wasm: *Wasm) !void {
26972721
2698 const object = &wasm.objects.items[sym_loc.file.?];2722 const object = &wasm.objects.items[sym_loc.file.?];
2699 const symbol = &object.symtable[sym_loc.index];2723 const symbol = &object.symtable[sym_loc.index];
2700 if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) {2724
2725 if (symbol.isDead() or
2726 symbol.isUndefined() or
2727 (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table))
2728 {
2701 // Skip undefined symbols as they go in the `import` section2729 // Skip undefined symbols as they go in the `import` section
2702 // Also skip symbols that do not need to have a section merged.2730 // Also skip symbols that do not need to have a section merged.
2703 continue;2731 continue;
...@@ -2753,8 +2781,8 @@ fn mergeTypes(wasm: *Wasm) !void {...@@ -2753,8 +2781,8 @@ fn mergeTypes(wasm: *Wasm) !void {
2753 }2781 }
2754 const object = wasm.objects.items[sym_loc.file.?];2782 const object = wasm.objects.items[sym_loc.file.?];
2755 const symbol = object.symtable[sym_loc.index];2783 const symbol = object.symtable[sym_loc.index];
2756 if (symbol.tag != .function) {2784 if (symbol.tag != .function or symbol.isDead()) {
2757 // Only functions have types2785 // Only functions have types. Only retrieve the type of referenced functions.
2758 continue;2786 continue;
2759 }2787 }
27602788
...@@ -3823,7 +3851,8 @@ fn writeToFile(...@@ -3823,7 +3851,8 @@ fn writeToFile(
3823 try leb.writeULEB128(binary_writer, @as(u32, @intCast(wasm.function_table.count())));3851 try leb.writeULEB128(binary_writer, @as(u32, @intCast(wasm.function_table.count())));
3824 var symbol_it = wasm.function_table.keyIterator();3852 var symbol_it = wasm.function_table.keyIterator();
3825 while (symbol_it.next()) |symbol_loc_ptr| {3853 while (symbol_it.next()) |symbol_loc_ptr| {
3826 try leb.writeULEB128(binary_writer, symbol_loc_ptr.*.getSymbol(wasm).index);3854 const sym = symbol_loc_ptr.*.getSymbol(wasm);
3855 try leb.writeULEB128(binary_writer, sym.index);
3827 }3856 }
38283857
3829 try writeVecSectionHeader(3858 try writeVecSectionHeader(