From e475ddb08e4bb3bacbc50bdd26fa83f579783dbb Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 1 Jan 2023 17:10:51 +0100 Subject: [PATCH] wasm-linker: export symbols by virtual address When exporting a data symbol, generate a regular global and use the data symbol's virtual addres as the value (init) of the global. --- src/link/Wasm.zig | 26 ++++++++------------------ src/link/Wasm/Atom.zig | 42 ++++++++++++++++++------------------------ 2 files changed, 26 insertions(+), 42 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 42cc2883e2..e03c8b1ba0 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{}, functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{}, /// Output global section wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{}, -/// Global symbols for exported data symbols -address_globals: std.ArrayListUnmanaged(SymbolLoc) = .{}, /// Memory section memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } }, /// Output table section @@ -880,7 +878,6 @@ pub fn deinit(wasm: *Wasm) void { wasm.func_types.deinit(gpa); wasm.functions.deinit(gpa); wasm.wasm_globals.deinit(gpa); - wasm.address_globals.deinit(gpa); wasm.function_table.deinit(gpa); wasm.tables.deinit(gpa); wasm.exports.deinit(gpa); @@ -1879,8 +1876,13 @@ fn setupExports(wasm: *Wasm) !void { break :blk try wasm.string_table.put(wasm.base.allocator, sym_name); }; const exp: types.Export = if (symbol.tag == .data) exp: { - const global_index = @intCast(u32, wasm.wasm_globals.items.len + wasm.address_globals.items.len); - try wasm.address_globals.append(wasm.base.allocator, sym_loc); + const atom = wasm.symbol_atom.get(sym_loc).?; + const va = atom.getVA(wasm, symbol); + const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len); + try wasm.wasm_globals.append(wasm.base.allocator, .{ + .global_type = .{ .valtype = .i32, .mutable = false }, + .init = .{ .i32_const = @intCast(i32, va) }, + }); break :exp .{ .name = export_name, .kind = .global, @@ -2741,22 +2743,10 @@ fn writeToFile( if (wasm.wasm_globals.items.len > 0) { const header_offset = try reserveVecSectionHeader(&binary_bytes); - var global_count: u32 = 0; for (wasm.wasm_globals.items) |global| { try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype)); try binary_writer.writeByte(@boolToInt(global.global_type.mutable)); try emitInit(binary_writer, global.init); - global_count += 1; - } - - for (wasm.address_globals.items) |sym_loc| { - const atom = wasm.symbol_atom.get(sym_loc).?; - try binary_writer.writeByte(std.wasm.valtype(.i32)); - try binary_writer.writeByte(0); // immutable - try emitInit(binary_writer, .{ - .i32_const = @bitCast(i32, atom.offset), - }); - global_count += 1; } try writeVecSectionHeader( @@ -2764,7 +2754,7 @@ fn writeToFile( header_offset, .global, @intCast(u32, binary_bytes.items.len - header_offset - header_size), - @intCast(u32, global_count), + @intCast(u32, wasm.wasm_globals.items.len), ); section_count += 1; } diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index eb3a31b8a0..de9cefebdc 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -90,24 +90,26 @@ pub fn getFirst(atom: *Atom) *Atom { return tmp; } -/// Unlike `getFirst` this returns the first `*Atom` that was -/// produced from Zig code, rather than an object file. -/// This is useful for debug sections where we want to extend -/// the bytes, and don't want to overwrite existing Atoms. -pub fn getFirstZigAtom(atom: *Atom) *Atom { - if (atom.file == null) return atom; - var tmp = atom; - return while (tmp.prev) |prev| { - if (prev.file == null) break prev; - tmp = prev; - } else unreachable; // must allocate an Atom first! -} - /// Returns the location of the symbol that represents this `Atom` pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc { return .{ .file = atom.file, .index = atom.sym_index }; } +/// Returns the virtual address of the `Atom`. This is the address starting +/// from the first entry within a section. +pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 { + if (symbol.tag == .function) return atom.offset; + std.debug.assert(symbol.tag == .data); + const merge_segment = wasm.base.options.output_mode != .Obj; + const segment_info = if (atom.file) |object_index| blk: { + break :blk wasm.objects.items[object_index].segment_info; + } else wasm.segment_info.values(); + const segment_name = segment_info[symbol.index].outputName(merge_segment); + const segment_index = wasm.data_segments.get(segment_name).?; + const segment = wasm.segments.items[segment_index]; + return segment.offset + atom.offset; +} + /// Resolves the relocations within the atom, writing the new value /// at the calculated offset. pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { @@ -159,7 +161,7 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void { /// The final value must be casted to the correct size. fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 { const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin); - const symbol = target_loc.getSymbol(wasm_bin).*; + const symbol = target_loc.getSymbol(wasm_bin); switch (relocation.relocation_type) { .R_WASM_FUNCTION_INDEX_LEB => return symbol.index, .R_WASM_TABLE_NUMBER_LEB => return symbol.index, @@ -190,17 +192,9 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa if (symbol.isUndefined()) { return 0; } - - const merge_segment = wasm_bin.base.options.output_mode != .Obj; const target_atom = wasm_bin.symbol_atom.get(target_loc).?; - const segment_info = if (target_atom.file) |object_index| blk: { - break :blk wasm_bin.objects.items[object_index].segment_info; - } else wasm_bin.segment_info.values(); - const segment_name = segment_info[symbol.index].outputName(merge_segment); - const segment_index = wasm_bin.data_segments.get(segment_name).?; - const segment = wasm_bin.segments.items[segment_index]; - const rel_value = @intCast(i32, target_atom.offset + segment.offset) + relocation.addend; - return @intCast(u32, rel_value); + const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol)); + return @intCast(u32, va + relocation.addend); }, .R_WASM_EVENT_INDEX_LEB => return symbol.index, .R_WASM_SECTION_OFFSET_I32 => {