From dd850929822abb7f81a0c4fdfa97ecf37d4bc16c Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 18 Dec 2022 16:37:00 +0100 Subject: [PATCH] wasm-linker: Fix relocations for alias'd atoms When an atom has one or multiple aliasses, we we could not find the target atom from the alias'd symbol. This is solved by ensuring that we also insert each alias symbol in the symbol-atom map. --- src/link/Wasm.zig | 36 +++++++++++++++++++++++++++--------- src/link/Wasm/Atom.zig | 6 +++++- src/link/Wasm/Object.zig | 8 ++++---- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index d8aab58ef1..6444b431be 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1568,9 +1568,13 @@ fn allocateAtoms(wasm: *Wasm) !void { var atom: *Atom = entry.value_ptr.*.getFirst(); var offset: u32 = 0; while (true) { + const symbol_loc = atom.symbolLoc(); + if (!wasm.resolved_symbols.contains(symbol_loc)) { + atom = atom.next orelse break; + continue; + } offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment); atom.offset = offset; - const symbol_loc = atom.symbolLoc(); log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ symbol_loc.getName(wasm), offset, @@ -1578,7 +1582,7 @@ fn allocateAtoms(wasm: *Wasm) !void { atom.size, }); offset += atom.size; - try wasm.symbol_atom.put(wasm.base.allocator, atom.symbolLoc(), atom); // Update atom pointers + try wasm.symbol_atom.put(wasm.base.allocator, symbol_loc, atom); // Update atom pointers atom = atom.next orelse break; } segment.size = std.mem.alignForwardGeneric(u32, offset, segment.alignment); @@ -2579,14 +2583,16 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l var atom: *Atom = wasm.atoms.get(code_index).?.getFirst(); // The code section must be sorted in line with the function order. - var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count()); + var sorted_atoms = try std.ArrayList(*Atom).initCapacity(gpa, wasm.functions.count()); defer sorted_atoms.deinit(); while (true) { - if (!is_obj) { - atom.resolveRelocs(wasm); + if (wasm.resolved_symbols.contains(atom.symbolLoc())) { + if (!is_obj) { + atom.resolveRelocs(wasm); + } + sorted_atoms.appendAssumeCapacity(atom); } - sorted_atoms.appendAssumeCapacity(atom); atom = atom.next orelse break; } @@ -2641,6 +2647,10 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l // fill in the offset table and the data segments var current_offset: u32 = 0; while (true) { + if (!wasm.resolved_symbols.contains(atom.symbolLoc())) { + atom = atom.next orelse break; + continue; + } if (!is_obj) { atom.resolveRelocs(wasm); } @@ -4170,15 +4180,23 @@ fn emitDataRelocations( try writeCustomSectionHeader(binary_bytes.items, header_offset, size); } -/// Searches for an a matching function signature, when not found -/// a new entry will be made. The index of the existing/new signature will be returned. -pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { +pub fn getTypeIndex(wasm: *const Wasm, func_type: std.wasm.Type) ?u32 { var index: u32 = 0; while (index < wasm.func_types.items.len) : (index += 1) { if (wasm.func_types.items[index].eql(func_type)) return index; } + return null; +} + +/// Searches for an a matching function signature, when not found +/// a new entry will be made. The index of the existing/new signature will be returned. +pub fn putOrGetFuncType(wasm: *Wasm, func_type: std.wasm.Type) !u32 { + if (wasm.getTypeIndex(func_type)) |index| { + return index; + } // functype does not exist. + const index = @intCast(u32, wasm.func_types.items.len); const params = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.params); errdefer wasm.base.allocator.free(params); const returns = try wasm.base.allocator.dupe(std.wasm.Valtype, func_type.returns); diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index f716cd56ee..eb3a31b8a0 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -186,7 +186,11 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa .R_WASM_MEMORY_ADDR_SLEB, .R_WASM_MEMORY_ADDR_SLEB64, => { - std.debug.assert(symbol.tag == .data and !symbol.isUndefined()); + std.debug.assert(symbol.tag == .data); + 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: { diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index e5947228a5..8f49d68712 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -923,7 +923,7 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b try atom.relocs.append(gpa, reloc); if (relocation.isTableIndex()) { - try wasm_bin.function_table.putNoClobber(gpa, .{ + try wasm_bin.function_table.put(gpa, .{ .file = object_index, .index = relocation.index, }, 0); @@ -938,17 +938,17 @@ pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_b .index = relocatable_data.getIndex(), })) |symbols| { atom.sym_index = symbols.pop(); + try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); // symbols referencing the same atom will be added as alias // or as 'parent' when they are global. while (symbols.popOrNull()) |idx| { + try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom); const alias_symbol = object.symtable[idx]; - const symbol = object.symtable[atom.sym_index]; - if (alias_symbol.isGlobal() and symbol.isLocal()) { + if (alias_symbol.isGlobal()) { atom.sym_index = idx; } } - try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); } const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];