Commit 7f508480f4

Luuk de Gram <luuk@degram.dev>
2022-10-08 11:00:07
wasm-linker: convert relocation addend to i32
Addends in relocations are signed integers as theoretically it could be a negative number. As Atom's offsets are relative to their parent section, the relocation value should still result in a postive number. For this reason, the final result is stored as an unsigned integer. Also, rather than using `null` for relocations that do not support addends. We set the value to 0 for those that do not support addends, and have to call `addendIsPresent` to determine if an addend exists or not. This means each Relocation costs 4 bytes less than before, saving memory while linking.
1 parent fa9327a
Changed files (5)
src/arch/wasm/Emit.zig
@@ -413,7 +413,7 @@ fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
             .offset = mem_offset,
             .index = mem.pointer,
             .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64,
-            .addend = mem.offset,
+            .addend = @intCast(i32, mem.offset),
         });
     }
 }
src/link/Wasm/Atom.zig
@@ -194,12 +194,14 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
             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];
-            return target_atom.offset + segment.offset + (relocation.addend orelse 0);
+            const rel_value = @intCast(i32, target_atom.offset + segment.offset) + relocation.addend;
+            return @intCast(u32, rel_value);
         },
         .R_WASM_EVENT_INDEX_LEB => return symbol.index,
         .R_WASM_SECTION_OFFSET_I32 => {
             const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
-            return target_atom.offset + (relocation.addend orelse 0);
+            const rel_value = @intCast(i32, target_atom.offset) + relocation.addend;
+            return @intCast(u32, rel_value);
         },
         .R_WASM_FUNCTION_OFFSET_I32 => {
             const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
@@ -214,7 +216,8 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
                 if (current_atom == target_atom) break;
                 current_atom = current_atom.next.?;
             }
-            return target_atom.offset + offset + (relocation.addend orelse 0);
+            const rel_value = @intCast(i32, target_atom.offset + offset) + relocation.addend;
+            return @intCast(u32, rel_value);
         },
     }
 }
src/link/Wasm/Object.zig
@@ -606,7 +606,7 @@ fn Parser(comptime ReaderType: type) type {
                     .relocation_type = rel_type_enum,
                     .offset = try leb.readULEB128(u32, reader),
                     .index = try leb.readULEB128(u32, reader),
-                    .addend = if (rel_type_enum.addendIsPresent()) try leb.readULEB128(u32, reader) else null,
+                    .addend = if (rel_type_enum.addendIsPresent()) try leb.readILEB128(i32, reader) else 0,
                 };
                 log.debug("Found relocation: type({s}) offset({d}) index({d}) addend({?d})", .{
                     @tagName(relocation.relocation_type),
src/link/Wasm/types.zig
@@ -12,8 +12,8 @@ pub const Relocation = struct {
     /// When the type is `R_WASM_TYPE_INDEX_LEB`, it represents the index of the type.
     index: u32,
     /// Addend to add to the address.
-    /// This field is only non-null for `R_WASM_MEMORY_ADDR_*`, `R_WASM_FUNCTION_OFFSET_I32` and `R_WASM_SECTION_OFFSET_I32`.
-    addend: ?u32 = null,
+    /// This field is only non-zero for `R_WASM_MEMORY_ADDR_*`, `R_WASM_FUNCTION_OFFSET_I32` and `R_WASM_SECTION_OFFSET_I32`.
+    addend: i32 = 0,
 
     /// All possible relocation types currently existing.
     /// This enum is exhaustive as the spec is WIP and new types
src/link/Wasm.zig
@@ -1080,7 +1080,7 @@ pub fn getDeclVAddr(
             .index = target_symbol_index,
             .offset = @intCast(u32, reloc_info.offset),
             .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
-            .addend = reloc_info.addend,
+            .addend = @intCast(i32, reloc_info.addend),
         });
     }
     // we do not know the final address at this point,
@@ -2001,7 +2001,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void {
             .index = names_symbol_index,
             .relocation_type = .R_WASM_MEMORY_ADDR_I32,
             .offset = offset,
-            .addend = addend,
+            .addend = @intCast(i32, addend),
         });
         atom.size += @intCast(u32, slice_ty.abiSize(wasm.base.options.target));
         addend += len;
@@ -3433,7 +3433,7 @@ fn emitCodeRelocations(
             try leb.writeULEB128(writer, offset);
             try leb.writeULEB128(writer, symbol_index);
             if (relocation.relocation_type.addendIsPresent()) {
-                try leb.writeULEB128(writer, relocation.addend orelse 0);
+                try leb.writeILEB128(writer, relocation.addend);
             }
             log.debug("Emit relocation: {}", .{relocation});
         }
@@ -3483,7 +3483,7 @@ fn emitDataRelocations(
                 try leb.writeULEB128(writer, offset);
                 try leb.writeULEB128(writer, symbol_index);
                 if (relocation.relocation_type.addendIsPresent()) {
-                    try leb.writeULEB128(writer, relocation.addend orelse 0);
+                    try leb.writeILEB128(writer, relocation.addend);
                 }
                 log.debug("Emit relocation: {}", .{relocation});
             }