authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-13 15:25:17+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-28 15:47:06+01:00
log589aef153709a3c1e0b1ee8af4bb4d710d46b792
tree17c85a238f5bf9584d9b8975333f792bcfec72c8
parentf3626eb81662fb7519d09e14bed6e4d958c73e43
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: mark symbols and its references

Symbols which are exported to the host, or contain the `NO_STRIP` flag, will be marked. All symbols which are referenced by this symbol are marked likewise. We achieve this by parsing all relocations of a symbol, and then marking the symbol it points to within the relocation.

2 files changed, 54 insertions(+), 1 deletions(-)

src/link/Wasm.zig+38-1
......@@ -3439,12 +3439,13 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
34393439
34403440 try wasm.setupInitFunctions();
34413441 try wasm.setupStart();
3442 try wasm.setupImports();
34433442
34443443 for (wasm.objects.items, 0..) |*object, object_index| {
34453444 try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm);
34463445 }
34473446
3447 wasm.markReferences();
3448 try wasm.setupImports();
34483449 try wasm.allocateAtoms();
34493450 try wasm.setupMemory();
34503451 wasm.allocateVirtualAddresses();
......@@ -3529,6 +3530,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
35293530 try wasm.setupInitFunctions();
35303531 try wasm.setupErrorsLen();
35313532 try wasm.setupStart();
3533 wasm.markReferences();
35323534 try wasm.setupImports();
35333535 if (wasm.base.options.module) |mod| {
35343536 var decl_it = wasm.decls.iterator();
......@@ -5026,3 +5028,38 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
50265028 try wasm.atom_types.put(wasm.base.allocator, atom_index, index);
50275029 return index;
50285030}
5031
5032/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
5033/// as well as any of its references.
5034fn markReferences(wasm: *Wasm) void {
5035 const tracy = trace(@src());
5036 defer tracy.end();
5037 for (wasm.resolved_symbols.keys()) |sym_loc| {
5038 const sym = sym_loc.getSymbol(wasm);
5039 if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {
5040 wasm.mark(sym_loc);
5041 }
5042 }
5043}
5044
5045/// Marks a symbol as 'alive' recursively so itself and any references it contains to
5046/// other symbols will not be omit from the binary.
5047fn mark(wasm: *Wasm, loc: SymbolLoc) void {
5048 const symbol = loc.getSymbol(wasm);
5049 if (symbol.isAlive()) {
5050 // Symbol is already marked alive, including its references.
5051 // This means we can skip it so we don't end up marking the same symbols
5052 // multiple times.
5053 return;
5054 }
5055 symbol.mark();
5056
5057 if (wasm.symbol_atom.get(loc)) |atom_index| {
5058 const atom = wasm.getAtom(atom_index);
5059 const relocations: []const types.Relocation = atom.relocs.items;
5060 for (relocations) |reloc| {
5061 const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };
5062 wasm.mark(target_loc.finalLoc(wasm));
5063 }
5064 }
5065}
src/link/Wasm/Symbol.zig+16
......@@ -79,6 +79,9 @@ pub const Flag = enum(u32) {
7979 WASM_SYM_NO_STRIP = 0x80,
8080 /// Indicates a symbol is TLS
8181 WASM_SYM_TLS = 0x100,
82 /// Zig specific flag. Uses the most significant bit of the flag to annotate whether a symbol is
83 /// alive or not. Dead symbols are allowed to be garbage collected.
84 alive = 0x80000000,
8285};
8386
8487/// Verifies if the given symbol should be imported from the
......@@ -92,6 +95,19 @@ pub fn requiresImport(symbol: Symbol) bool {
9295 return true;
9396}
9497
98/// Marks a symbol as 'alive', ensuring the garbage collector will not collect the trash.
99pub fn mark(symbol: *Symbol) void {
100 symbol.flags |= @intFromEnum(Flag.alive);
101}
102
103pub fn isAlive(symbol: Symbol) bool {
104 return symbol.flags & @intFromEnum(Flag.alive) != 0;
105}
106
107pub fn isDead(symbol: Symbol) bool {
108 return symbol.flags & @intFromEnum(Flag.alive) == 0;
109}
110
95111pub fn isTLS(symbol: Symbol) bool {
96112 return symbol.flags & @intFromEnum(Flag.WASM_SYM_TLS) != 0;
97113}