authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-01-01 17:10:51+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-01-02 18:36:18+01:00
loge475ddb08e4bb3bacbc50bdd26fa83f579783dbb
tree366a5b3b61c6598b23bc7e8a3551860ba9ac39af
parent86ed96d9336c06668a727893e41856b2e4fe3d23
signaturelock-open Commit is signed but in an unrecognized format.

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.

2 files changed, 26 insertions(+), 42 deletions(-)

src/link/Wasm.zig+8-18
......@@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},
112112functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{},
113113/// Output global section
114114wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
115/// Global symbols for exported data symbols
116address_globals: std.ArrayListUnmanaged(SymbolLoc) = .{},
117115/// Memory section
118116memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
119117/// Output table section
......@@ -880,7 +878,6 @@ pub fn deinit(wasm: *Wasm) void {
880878 wasm.func_types.deinit(gpa);
881879 wasm.functions.deinit(gpa);
882880 wasm.wasm_globals.deinit(gpa);
883 wasm.address_globals.deinit(gpa);
884881 wasm.function_table.deinit(gpa);
885882 wasm.tables.deinit(gpa);
886883 wasm.exports.deinit(gpa);
......@@ -1879,8 +1876,13 @@ fn setupExports(wasm: *Wasm) !void {
18791876 break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
18801877 };
18811878 const exp: types.Export = if (symbol.tag == .data) exp: {
1882 const global_index = @intCast(u32, wasm.wasm_globals.items.len + wasm.address_globals.items.len);
1883 try wasm.address_globals.append(wasm.base.allocator, sym_loc);
1879 const atom = wasm.symbol_atom.get(sym_loc).?;
1880 const va = atom.getVA(wasm, symbol);
1881 const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);
1882 try wasm.wasm_globals.append(wasm.base.allocator, .{
1883 .global_type = .{ .valtype = .i32, .mutable = false },
1884 .init = .{ .i32_const = @intCast(i32, va) },
1885 });
18841886 break :exp .{
18851887 .name = export_name,
18861888 .kind = .global,
......@@ -2741,22 +2743,10 @@ fn writeToFile(
27412743 if (wasm.wasm_globals.items.len > 0) {
27422744 const header_offset = try reserveVecSectionHeader(&binary_bytes);
27432745
2744 var global_count: u32 = 0;
27452746 for (wasm.wasm_globals.items) |global| {
27462747 try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype));
27472748 try binary_writer.writeByte(@boolToInt(global.global_type.mutable));
27482749 try emitInit(binary_writer, global.init);
2749 global_count += 1;
2750 }
2751
2752 for (wasm.address_globals.items) |sym_loc| {
2753 const atom = wasm.symbol_atom.get(sym_loc).?;
2754 try binary_writer.writeByte(std.wasm.valtype(.i32));
2755 try binary_writer.writeByte(0); // immutable
2756 try emitInit(binary_writer, .{
2757 .i32_const = @bitCast(i32, atom.offset),
2758 });
2759 global_count += 1;
27602750 }
27612751
27622752 try writeVecSectionHeader(
......@@ -2764,7 +2754,7 @@ fn writeToFile(
27642754 header_offset,
27652755 .global,
27662756 @intCast(u32, binary_bytes.items.len - header_offset - header_size),
2767 @intCast(u32, global_count),
2757 @intCast(u32, wasm.wasm_globals.items.len),
27682758 );
27692759 section_count += 1;
27702760 }
src/link/Wasm/Atom.zig+18-24
......@@ -90,24 +90,26 @@ pub fn getFirst(atom: *Atom) *Atom {
9090 return tmp;
9191}
9292
93/// Unlike `getFirst` this returns the first `*Atom` that was
94/// produced from Zig code, rather than an object file.
95/// This is useful for debug sections where we want to extend
96/// the bytes, and don't want to overwrite existing Atoms.
97pub fn getFirstZigAtom(atom: *Atom) *Atom {
98 if (atom.file == null) return atom;
99 var tmp = atom;
100 return while (tmp.prev) |prev| {
101 if (prev.file == null) break prev;
102 tmp = prev;
103 } else unreachable; // must allocate an Atom first!
104}
105
10693/// Returns the location of the symbol that represents this `Atom`
10794pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
10895 return .{ .file = atom.file, .index = atom.sym_index };
10996}
11097
98/// Returns the virtual address of the `Atom`. This is the address starting
99/// from the first entry within a section.
100pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 {
101 if (symbol.tag == .function) return atom.offset;
102 std.debug.assert(symbol.tag == .data);
103 const merge_segment = wasm.base.options.output_mode != .Obj;
104 const segment_info = if (atom.file) |object_index| blk: {
105 break :blk wasm.objects.items[object_index].segment_info;
106 } else wasm.segment_info.values();
107 const segment_name = segment_info[symbol.index].outputName(merge_segment);
108 const segment_index = wasm.data_segments.get(segment_name).?;
109 const segment = wasm.segments.items[segment_index];
110 return segment.offset + atom.offset;
111}
112
111113/// Resolves the relocations within the atom, writing the new value
112114/// at the calculated offset.
113115pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
......@@ -159,7 +161,7 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
159161/// The final value must be casted to the correct size.
160162fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
161163 const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin);
162 const symbol = target_loc.getSymbol(wasm_bin).*;
164 const symbol = target_loc.getSymbol(wasm_bin);
163165 switch (relocation.relocation_type) {
164166 .R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
165167 .R_WASM_TABLE_NUMBER_LEB => return symbol.index,
......@@ -190,17 +192,9 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
190192 if (symbol.isUndefined()) {
191193 return 0;
192194 }
193
194 const merge_segment = wasm_bin.base.options.output_mode != .Obj;
195195 const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
196 const segment_info = if (target_atom.file) |object_index| blk: {
197 break :blk wasm_bin.objects.items[object_index].segment_info;
198 } else wasm_bin.segment_info.values();
199 const segment_name = segment_info[symbol.index].outputName(merge_segment);
200 const segment_index = wasm_bin.data_segments.get(segment_name).?;
201 const segment = wasm_bin.segments.items[segment_index];
202 const rel_value = @intCast(i32, target_atom.offset + segment.offset) + relocation.addend;
203 return @intCast(u32, rel_value);
196 const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));
197 return @intCast(u32, va + relocation.addend);
204198 },
205199 .R_WASM_EVENT_INDEX_LEB => return symbol.index,
206200 .R_WASM_SECTION_OFFSET_I32 => {