commit 5468684456b13b6465c4fcd50c072e5d5c8536a3 (tree)
parent c77ca9174976a9fb8769276ce913e761d66af1de
Author: Luuk de Gram <luuk@degram.dev>
Date: Fri, 13 Jan 2023 06:31:00 +0100
wasm-linker: implement the __heap_end symbol
When any of the object files reference the __heap_end symbol, we will
create it as a synthetic symbol. The symbol only exists within the
linker and will not be emit within the binary as it's solely used for
relocations. The symbol represents where the heap ends, so allocators
can determine whether to allocate a new page or not.
Diffstat:
1 file changed, 30 insertions(+), 10 deletions(-)
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
@@ -871,6 +871,22 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
try wasm.parseAtom(atom, .{ .data = .synthetic });
try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
}
+
+ if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {
+ const loc = try wasm.createSyntheticSymbol("__heap_end", .data);
+ try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
+ _ = wasm.resolved_symbols.swapRemove(loc);
+
+ const atom = try wasm.base.allocator.create(Atom);
+ errdefer wasm.base.allocator.destroy(atom);
+ try wasm.managed_atoms.append(wasm.base.allocator, atom);
+ atom.* = Atom.empty;
+ atom.sym_index = loc.index;
+ atom.alignment = 1;
+
+ try wasm.parseAtom(atom, .{ .data = .synthetic });
+ try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
+ }
}
// Tries to find a global symbol by its name. Returns null when not found,
@@ -892,14 +908,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
const file_name = if (undef.file) |file_index| name: {
break :name wasm.objects.items[file_index].name;
} else wasm.name;
- const import_name = if (undef.file) |file_index| name: {
- const obj = wasm.objects.items[file_index];
- const name_index = if (symbol.tag == .function) name_index: {
- break :name_index obj.findImport(symbol.tag.externalType(), symbol.index).name;
- } else symbol.name;
- break :name obj.string_table.get(name_index);
- } else wasm.string_table.get(wasm.imports.get(undef).?.name);
- log.err("could not resolve undefined symbol '{s}'", .{import_name});
+ const symbol_name = undef.getName(wasm);
+ log.err("could not resolve undefined symbol '{s}'", .{symbol_name});
log.err(" defined in '{s}'", .{file_name});
}
}
@@ -2223,12 +2233,20 @@ fn setupMemory(wasm: *Wasm) !void {
}
memory_ptr = initial_memory;
}
-
+ memory_ptr = mem.alignForwardGeneric(u64, memory_ptr, std.wasm.page_size);
// In case we do not import memory, but define it ourselves,
// set the minimum amount of pages on the memory section.
- wasm.memories.limits.min = @intCast(u32, std.mem.alignForwardGeneric(u64, memory_ptr, page_size) / page_size);
+ wasm.memories.limits.min = @intCast(u32, memory_ptr / page_size);
log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
+ if (wasm.findGlobalSymbol("__heap_end")) |loc| {
+ const segment_index = wasm.data_segments.get(".synthetic").?;
+ const segment = &wasm.segments.items[segment_index];
+ segment.offset = 0;
+ const atom = wasm.symbol_atom.get(loc).?;
+ atom.offset = @intCast(u32, memory_ptr);
+ }
+
if (wasm.base.options.max_memory) |max_memory| {
if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {
log.err("Maximum memory must be {d}-byte aligned", .{page_size});
@@ -3392,6 +3410,8 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
// bss section is not emitted when this condition holds true, so we also
// do not output a name for it.
if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
+ // Synthetic segments are not emitted
+ if (std.mem.eql(u8, key, ".synthetic")) continue;
segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
data_segment_index += 1;
}