diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e610d56df4..671425ab71 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -862,7 +862,8 @@ pub fn commitDeclState( .wasm => { const wasm_file = file.cast(File.Wasm).?; const segment_index = wasm_file.debug_line_index.?; - const debug_line = wasm_file.atoms.get(segment_index).?.code; + const atom = wasm_file.atoms.get(segment_index).?; + const debug_line = atom.getFirstZigAtom().code; writeDbgLineNopsBuffered(debug_line.items, src_fn.off, 0, &.{}, src_fn.len); }, else => unreachable, @@ -974,9 +975,10 @@ pub fn commitDeclState( }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - const segment_index = try wasm_file.getOrSetDebugIndex(&wasm_file.debug_line_index); + const segment_index = wasm_file.debug_line_index.?; const segment = &wasm_file.segments.items[segment_index]; - const debug_line = &wasm_file.atoms.get(segment_index).?.code; + const atom = wasm_file.atoms.get(segment_index).?; + const debug_line = &atom.getFirstZigAtom().code; if (needed_size != segment.size) { log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); if (needed_size > segment.size) { @@ -1148,9 +1150,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - const segment_index = try wasm_file.getOrSetDebugIndex(&wasm_file.debug_info_index); + const segment_index = wasm_file.debug_info_index.?; const segment = &wasm_file.segments.items[segment_index]; - const debug_info = &wasm_file.atoms.get(segment_index).?.code; + const info_atom = wasm_file.atoms.get(segment_index).?; + const debug_info = &info_atom.getFirstZigAtom().code; const offset = segment.offset + atom.off; try writeDbgInfoNopsToArrayList(gpa, debug_info, offset, 0, &.{0}, atom.len, false); }, @@ -1279,9 +1282,10 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - const segment_index = try wasm_file.getOrSetDebugIndex(&wasm_file.debug_info_index); + const segment_index = wasm_file.debug_info_index.?; const segment = &wasm_file.segments.items[segment_index]; - const debug_info = &wasm_file.atoms.get(segment_index).?.code; + const info_atom = wasm_file.atoms.get(segment_index).?; + const debug_info = &info_atom.getFirstZigAtom().code; if (needed_size != segment.size) { log.debug(" needed size does not equal allocated size: {d}", .{needed_size}); if (needed_size > segment.size) { @@ -1343,7 +1347,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, file: *File, decl: *const Module.Decl) const segment_index = wasm_file.debug_line_index.?; const segment = wasm_file.segments.items[segment_index]; const offset = segment.offset + decl.fn_link.wasm.src_fn.off + self.getRelocDbgLineOff(); - mem.copy(u8, wasm_file.atoms.get(segment_index).?.code.items[offset..], &data); + const atom = wasm_file.atoms.get(segment_index).?.getFirstZigAtom(); + mem.copy(u8, atom.code.items[offset..], &data); }, else => unreachable, } @@ -1579,8 +1584,8 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void { }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - const segment_index = try wasm_file.getOrSetDebugIndex(&wasm_file.debug_abbrev_index); - const debug_abbrev = &wasm_file.atoms.get(segment_index).?.code; + const segment_index = wasm_file.debug_abbrev_index.?; + const debug_abbrev = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code; try debug_abbrev.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_abbrev.items, &abbrev_buf); }, @@ -1693,7 +1698,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 .wasm => { const wasm_file = file.cast(File.Wasm).?; const segment_index = wasm_file.debug_info_index.?; - const debug_info = &wasm_file.atoms.get(segment_index).?.code; + const debug_info = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code; try writeDbgInfoNopsToArrayList(self.allocator, debug_info, 0, 0, di_buf.items, jmp_amt, false); }, else => unreachable, @@ -2023,8 +2028,8 @@ pub fn writeDbgAranges(self: *Dwarf, file: *File, addr: u64, size: u64) !void { }, .wasm => { const wasm_file = file.cast(File.Wasm).?; - const segment_index = try wasm_file.getOrSetDebugIndex(&wasm_file.debug_ranges_index); - const debug_ranges = &wasm_file.atoms.get(segment_index).?.code; + const segment_index = wasm_file.debug_ranges_index.?; + const debug_ranges = &wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code; try debug_ranges.resize(wasm_file.base.allocator, needed_size); mem.copy(u8, debug_ranges.items, di_buf.items); }, @@ -2149,7 +2154,7 @@ pub fn writeDbgLineHeader(self: *Dwarf, file: *File, module: *Module) !void { .wasm => { const wasm_file = file.cast(File.Wasm).?; const segment_index = wasm_file.debug_line_index.?; - const debug_line = wasm_file.atoms.get(segment_index).?.code; + const debug_line = wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code; writeDbgLineNopsBuffered(debug_line.items, 0, 0, di_buf.items, jmp_amt); }, else => unreachable, @@ -2299,7 +2304,7 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { .wasm => { const wasm_file = file.cast(File.Wasm).?; const segment_index = wasm_file.debug_info_index.?; - const debug_info = wasm_file.atoms.get(segment_index).?.code; + const debug_info = wasm_file.atoms.get(segment_index).?.getFirstZigAtom().code; mem.copy(u8, debug_info.items[reloc.atom.off + reloc.offset ..], &buf); }, else => unreachable, diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 7204182df2..67f229ca84 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -349,6 +349,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option }; } + try wasm_bin.initDebugSections(); return wasm_bin; } @@ -377,6 +378,23 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm { return self; } +/// Initializes symbols and atoms for the debug sections +/// Initialization is only done when compiling Zig code. +/// When Zig is invoked as a linker instead, the atoms +/// and symbols come from the object files instead. +pub fn initDebugSections(self: *Wasm) !void { + if (self.dwarf == null) return; // not compiling Zig code, so no need to pre-initialize debug sections + // this will create an Atom and set the index for us. + try self.createDebugSectionForIndex(&self.debug_info_index); + try self.createDebugSectionForIndex(&self.debug_line_index); + try self.createDebugSectionForIndex(&self.debug_loc_index); + try self.createDebugSectionForIndex(&self.debug_abbrev_index); + try self.createDebugSectionForIndex(&self.debug_ranges_index); + try self.createDebugSectionForIndex(&self.debug_str_index); + try self.createDebugSectionForIndex(&self.debug_pubnames_index); + try self.createDebugSectionForIndex(&self.debug_pubtypes_index); +} + fn parseInputFiles(self: *Wasm, files: []const []const u8) !void { for (files) |path| { if (try self.parseObjectFile(path)) continue; @@ -1968,23 +1986,19 @@ fn populateErrorNameTable(self: *Wasm) !void { try self.parseAtom(names_atom, .{ .data = .read_only }); } -/// From a given index variable, returns it value if set. -/// When not set, initialises a new segment, sets the index, -/// and returns it value. -/// When a new segment is initialised. It also creates an atom. -pub fn getOrSetDebugIndex(self: *Wasm, index: *?u32) !u32 { - return (index.*) orelse { - const new_index = @intCast(u32, self.segments.items.len); - index.* = new_index; - try self.appendDummySegment(); +/// From a given index variable, creates a new debug section. +/// This initializes the index, appends a new segment, +/// and finally, creates a managed `Atom`. +pub fn createDebugSectionForIndex(self: *Wasm, index: *?u32) !void { + const new_index = @intCast(u32, self.segments.items.len); + index.* = new_index; + try self.appendDummySegment(); - const atom = try self.base.allocator.create(Atom); - atom.* = Atom.empty; - atom.alignment = 1; // debug sections are always 1-byte-aligned - try self.managed_atoms.append(self.base.allocator, atom); - try self.atoms.put(self.base.allocator, new_index, atom); - return new_index; - }; + const atom = try self.base.allocator.create(Atom); + atom.* = Atom.empty; + atom.alignment = 1; // debug sections are always 1-byte-aligned + try self.managed_atoms.append(self.base.allocator, atom); + try self.atoms.put(self.base.allocator, new_index, atom); } fn resetState(self: *Wasm) void { diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index 64efa8320f..440ebea6f4 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -90,6 +90,19 @@ pub fn getFirst(self: *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(self: *Atom) *Atom { + if (self.file == null) return self; + var tmp = self; + 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(self: Atom) Wasm.SymbolLoc { return .{ .file = self.file, .index = self.sym_index }; @@ -184,8 +197,24 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa return target_atom.offset + segment.offset + (relocation.addend orelse 0); }, .R_WASM_EVENT_INDEX_LEB => return symbol.index, - .R_WASM_SECTION_OFFSET_I32, - .R_WASM_FUNCTION_OFFSET_I32, - => return relocation.addend orelse 0, + .R_WASM_SECTION_OFFSET_I32 => { + const target_atom = wasm_bin.symbol_atom.get(target_loc).?; + return target_atom.offset + (relocation.addend orelse 0); + }, + .R_WASM_FUNCTION_OFFSET_I32 => { + const target_atom = wasm_bin.symbol_atom.get(target_loc).?; + var atom = target_atom.getFirst(); + var offset: u32 = 0; + // TODO: Calculate this during atom allocation, rather than + // this linear calculation. For now it's done here as atoms + // are being sorted after atom allocation, as functions aren't + // merged until later. + while (true) { + offset += 5; // each atom uses 5 bytes to store its body's size + if (atom == target_atom) break; + atom = atom.next.?; + } + return target_atom.offset + offset + (relocation.addend orelse 0); + }, } }