From 5468684456b13b6465c4fcd50c072e5d5c8536a3 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Fri, 13 Jan 2023 06:31:00 +0100 Subject: [PATCH] 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. --- src/link/Wasm.zig | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 4abf12a2de..7154cd7bc1 100644 --- 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; }