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.
This commit is contained in:
@@ -3439,12 +3439,13 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
|
||||
|
||||
try wasm.setupInitFunctions();
|
||||
try wasm.setupStart();
|
||||
try wasm.setupImports();
|
||||
|
||||
for (wasm.objects.items, 0..) |*object, object_index| {
|
||||
try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm);
|
||||
}
|
||||
|
||||
wasm.markReferences();
|
||||
try wasm.setupImports();
|
||||
try wasm.allocateAtoms();
|
||||
try wasm.setupMemory();
|
||||
wasm.allocateVirtualAddresses();
|
||||
@@ -3529,6 +3530,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
try wasm.setupInitFunctions();
|
||||
try wasm.setupErrorsLen();
|
||||
try wasm.setupStart();
|
||||
wasm.markReferences();
|
||||
try wasm.setupImports();
|
||||
if (wasm.base.options.module) |mod| {
|
||||
var decl_it = wasm.decls.iterator();
|
||||
@@ -5026,3 +5028,38 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
|
||||
try wasm.atom_types.put(wasm.base.allocator, atom_index, index);
|
||||
return index;
|
||||
}
|
||||
|
||||
/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
|
||||
/// as well as any of its references.
|
||||
fn markReferences(wasm: *Wasm) void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
for (wasm.resolved_symbols.keys()) |sym_loc| {
|
||||
const sym = sym_loc.getSymbol(wasm);
|
||||
if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {
|
||||
wasm.mark(sym_loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks a symbol as 'alive' recursively so itself and any references it contains to
|
||||
/// other symbols will not be omit from the binary.
|
||||
fn mark(wasm: *Wasm, loc: SymbolLoc) void {
|
||||
const symbol = loc.getSymbol(wasm);
|
||||
if (symbol.isAlive()) {
|
||||
// Symbol is already marked alive, including its references.
|
||||
// This means we can skip it so we don't end up marking the same symbols
|
||||
// multiple times.
|
||||
return;
|
||||
}
|
||||
symbol.mark();
|
||||
|
||||
if (wasm.symbol_atom.get(loc)) |atom_index| {
|
||||
const atom = wasm.getAtom(atom_index);
|
||||
const relocations: []const types.Relocation = atom.relocs.items;
|
||||
for (relocations) |reloc| {
|
||||
const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };
|
||||
wasm.mark(target_loc.finalLoc(wasm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,9 @@ pub const Flag = enum(u32) {
|
||||
WASM_SYM_NO_STRIP = 0x80,
|
||||
/// Indicates a symbol is TLS
|
||||
WASM_SYM_TLS = 0x100,
|
||||
/// Zig specific flag. Uses the most significant bit of the flag to annotate whether a symbol is
|
||||
/// alive or not. Dead symbols are allowed to be garbage collected.
|
||||
alive = 0x80000000,
|
||||
};
|
||||
|
||||
/// Verifies if the given symbol should be imported from the
|
||||
@@ -92,6 +95,19 @@ pub fn requiresImport(symbol: Symbol) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Marks a symbol as 'alive', ensuring the garbage collector will not collect the trash.
|
||||
pub fn mark(symbol: *Symbol) void {
|
||||
symbol.flags |= @intFromEnum(Flag.alive);
|
||||
}
|
||||
|
||||
pub fn isAlive(symbol: Symbol) bool {
|
||||
return symbol.flags & @intFromEnum(Flag.alive) != 0;
|
||||
}
|
||||
|
||||
pub fn isDead(symbol: Symbol) bool {
|
||||
return symbol.flags & @intFromEnum(Flag.alive) == 0;
|
||||
}
|
||||
|
||||
pub fn isTLS(symbol: Symbol) bool {
|
||||
return symbol.flags & @intFromEnum(Flag.WASM_SYM_TLS) != 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user