Commit f2c8d09c4f
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);
+ },
}
}
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,
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();
-
- 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;
- };
+/// 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);
}
fn resetState(self: *Wasm) void {