authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-01-13 06:31:00+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-01-13 16:41:27+01:00
log5468684456b13b6465c4fcd50c072e5d5c8536a3
tree11bc75c13275bc6328c3a2efefff059ce73c0f3b
parentc77ca9174976a9fb8769276ce913e761d66af1de
signaturelock-open Commit is signed but in an unrecognized format.

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.

1 files changed, 30 insertions(+), 10 deletions(-)

src/link/Wasm.zig+30-10
...@@ -871,6 +871,22 @@ fn resolveLazySymbols(wasm: *Wasm) !void {...@@ -871,6 +871,22 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
871 try wasm.parseAtom(atom, .{ .data = .synthetic });871 try wasm.parseAtom(atom, .{ .data = .synthetic });
872 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);872 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
873 }873 }
874
875 if (wasm.undefs.fetchSwapRemove("__heap_end")) |kv| {
876 const loc = try wasm.createSyntheticSymbol("__heap_end", .data);
877 try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
878 _ = wasm.resolved_symbols.swapRemove(loc);
879
880 const atom = try wasm.base.allocator.create(Atom);
881 errdefer wasm.base.allocator.destroy(atom);
882 try wasm.managed_atoms.append(wasm.base.allocator, atom);
883 atom.* = Atom.empty;
884 atom.sym_index = loc.index;
885 atom.alignment = 1;
886
887 try wasm.parseAtom(atom, .{ .data = .synthetic });
888 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom);
889 }
874}890}
875891
876// Tries to find a global symbol by its name. Returns null when not found,892// Tries to find a global symbol by its name. Returns null when not found,
...@@ -892,14 +908,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {...@@ -892,14 +908,8 @@ fn checkUndefinedSymbols(wasm: *const Wasm) !void {
892 const file_name = if (undef.file) |file_index| name: {908 const file_name = if (undef.file) |file_index| name: {
893 break :name wasm.objects.items[file_index].name;909 break :name wasm.objects.items[file_index].name;
894 } else wasm.name;910 } else wasm.name;
895 const import_name = if (undef.file) |file_index| name: {911 const symbol_name = undef.getName(wasm);
896 const obj = wasm.objects.items[file_index];912 log.err("could not resolve undefined symbol '{s}'", .{symbol_name});
897 const name_index = if (symbol.tag == .function) name_index: {
898 break :name_index obj.findImport(symbol.tag.externalType(), symbol.index).name;
899 } else symbol.name;
900 break :name obj.string_table.get(name_index);
901 } else wasm.string_table.get(wasm.imports.get(undef).?.name);
902 log.err("could not resolve undefined symbol '{s}'", .{import_name});
903 log.err(" defined in '{s}'", .{file_name});913 log.err(" defined in '{s}'", .{file_name});
904 }914 }
905 }915 }
...@@ -2223,12 +2233,20 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2223,12 +2233,20 @@ fn setupMemory(wasm: *Wasm) !void {
2223 }2233 }
2224 memory_ptr = initial_memory;2234 memory_ptr = initial_memory;
2225 }2235 }
22262236 memory_ptr = mem.alignForwardGeneric(u64, memory_ptr, std.wasm.page_size);
2227 // In case we do not import memory, but define it ourselves,2237 // In case we do not import memory, but define it ourselves,
2228 // set the minimum amount of pages on the memory section.2238 // set the minimum amount of pages on the memory section.
2229 wasm.memories.limits.min = @intCast(u32, std.mem.alignForwardGeneric(u64, memory_ptr, page_size) / page_size);2239 wasm.memories.limits.min = @intCast(u32, memory_ptr / page_size);
2230 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});2240 log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
22312241
2242 if (wasm.findGlobalSymbol("__heap_end")) |loc| {
2243 const segment_index = wasm.data_segments.get(".synthetic").?;
2244 const segment = &wasm.segments.items[segment_index];
2245 segment.offset = 0;
2246 const atom = wasm.symbol_atom.get(loc).?;
2247 atom.offset = @intCast(u32, memory_ptr);
2248 }
2249
2232 if (wasm.base.options.max_memory) |max_memory| {2250 if (wasm.base.options.max_memory) |max_memory| {
2233 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {2251 if (!std.mem.isAlignedGeneric(u64, max_memory, page_size)) {
2234 log.err("Maximum memory must be {d}-byte aligned", .{page_size});2252 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...@@ -3392,6 +3410,8 @@ fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem
3392 // bss section is not emitted when this condition holds true, so we also3410 // bss section is not emitted when this condition holds true, so we also
3393 // do not output a name for it.3411 // do not output a name for it.
3394 if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;3412 if (!wasm.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
3413 // Synthetic segments are not emitted
3414 if (std.mem.eql(u8, key, ".synthetic")) continue;
3395 segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });3415 segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
3396 data_segment_index += 1;3416 data_segment_index += 1;
3397 }3417 }