Commit e475ddb08e

Luuk de Gram <luuk@degram.dev>
2023-01-01 17:10:51
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.
1 parent 86ed96d
Changed files (2)
src
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 => {
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;
     }