From a059c9a5e57164338bf4b99728905882b0d6323c Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 7 Sep 2026 19:37:01 -0400 Subject: [PATCH] Dwarf2: use indexed addresses This saves another ~70MB. --- src/codegen/x86_64/Emit.zig | 31 ++++---- src/link/Dwarf2.zig | 136 ++++++++++++++++++++++++++++-------- src/link/Elf2.zig | 119 ++++++++++++++++++++++++++----- 3 files changed, 228 insertions(+), 58 deletions(-) diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig index 7196aca6ef02eee3b07bcdf58d84822ee550877d..0955a8d91b10ad9687fb522e76db3a03778258f0 100644 --- a/src/codegen/x86_64/Emit.zig +++ b/src/codegen/x86_64/Emit.zig @@ -552,9 +552,9 @@ pub fn emitMir(emit: *Emit) Error!void { .pseudo_dbg_var_m, => switch (emit.debug_output) { inline .dwarf, .dwarf2 => |dwarf, tag| { - const DwarfLoc = switch (tag) { - .dwarf => link.File.Dwarf.Loc, - .dwarf2 => link.File.Dwarf2.Loc, + const DwarfLoc, const addr_loc = switch (tag) { + .dwarf => .{ link.File.Dwarf.Loc, "addr_reloc" }, + .dwarf2 => .{ link.File.Dwarf2.Loc, "addrx_sym" }, .eh_frame, .none => comptime unreachable, }; var loc_buf: [2]DwarfLoc = undefined; @@ -597,16 +597,21 @@ pub fn emitMir(emit: *Emit) Error!void { .none => .{ .constu = 0 }, .reg => |reg| .{ .breg = reg.dwarfNum() }, .frame, .table, .rip_inst => unreachable, - .nav => |nav| .{ .addr_reloc = try codegen.genNavRef( - emit.bin_file, - emit.pt, - nav, - ) }, - .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav( - emit.pt, - uav.val, - Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu), - ) }, + .nav => |nav| @unionInit( + DwarfLoc, + addr_loc, + try codegen.genNavRef(emit.bin_file, emit.pt, nav), + ), + .uav => |uav| @unionInit( + DwarfLoc, + addr_loc, + try emit.bin_file.lowerUav( + emit.pt, + uav.val, + Type.fromInterned(uav.orig_ty) + .ptrAlignment(emit.pt.zcu), + ), + ), .lazy_sym, .extern_func => unreachable, }; break :base &loc_buf[0]; diff --git a/src/link/Dwarf2.zig b/src/link/Dwarf2.zig index e1045dcfdca19ef61576f972b893204c988228f8..0f388714b3a3646ccbc7b17b0c557abf74606497 100644 --- a/src/link/Dwarf2.zig +++ b/src/link/Dwarf2.zig @@ -13,6 +13,7 @@ decls: std.array_hash_map.Auto(InternPool.TrackedInst.Index, Decl), pending_decl: struct { di: Decl.Index, instance: Decl.Instance }, debug_abbrev: Abbrev, +debug_addr: Addr, frame: Frame, debug_info: Info, debug_line: Line, @@ -182,6 +183,29 @@ pub const Abbrev = struct { set: std.enums.EnumSet(AbbrevCode), }; +pub const Addr = struct { + ni: link.MappedFile.Node.Index.Optional, + pending_index: usize, + map: std.array_hash_map.Auto(link.File.SymbolId, void), + + fn get(a: *Addr, gpa: std.mem.Allocator, si: link.File.SymbolId) std.mem.Allocator.Error!usize { + const gop = try a.map.getOrPut(gpa, si); + return gop.index; + } + + fn tableOffset(dwarf: *Dwarf) usize { + return dwarf.unitLengthSize() + 2 + 1 + 1; + } + + pub fn size(a: *Addr, dwarf: *Dwarf) usize { + return tableOffset(dwarf) + @backingInt(dwarf.address_size) * a.pending_index; + } + + pub fn anyPending(a: *Addr) bool { + return a.map.count() - a.pending_index > 0; + } +}; + pub const Info = struct {}; pub const Line = struct { @@ -274,12 +298,14 @@ pub const StrOffsets = struct { ) link.Error!usize { const comp = dwarf.lf.comp; try so.map.ensureUnusedCapacity(comp.gpa, 1); - return so.map.getOrPutAssumeCapacity(s.get(comp.gpa, mf, str) catch |err| switch (err) { + const offset = s.get(comp.gpa, mf, str) catch |err| switch (err) { else => |e| return e, error.MappedFileIo => return comp.link_diags.fail("failed to write output file: {t}", .{ mf.io_err.?, }), - }).index; + }; + const gop = so.map.getOrPutAssumeCapacity(offset); + return gop.index; } fn tableOffset(dwarf: *Dwarf) usize { @@ -289,13 +315,20 @@ pub const StrOffsets = struct { pub fn size(so: *StrOffsets, dwarf: *Dwarf) usize { return tableOffset(dwarf) + dwarf.secOffsetSize() * so.pending_index; } + + pub fn anyPending(so: *StrOffsets) bool { + return so.map.count() - so.pending_index > 0; + } }; pub const SharedSection = enum { debug_abbrev, debug_line_str, debug_str }; pub const Loc = union(enum) { empty, - addr_reloc: link.File.SymbolId, + addr_sym: struct { + si: link.File.SymbolId, + offset: usize = 0, + }, deref: *const Loc, constu: u64, consts: i64, @@ -314,6 +347,8 @@ pub const Loc = union(enum) { node: link.MappedFile.Node.Index, offset: i65 = 0, }, + addrx_sym: link.File.SymbolId, + constx_sym: link.File.SymbolId, wasm_ext: union(enum) { local: u32, global: u32, @@ -356,11 +391,11 @@ pub const Loc = union(enum) { }; switch (loc) { .empty => {}, - .addr_reloc => |si| { + .addr_sym => |sym| { try w.writeByte(DW.OP.addr); switch (writer) { .io => try dwarf.addrPlaceholder(w), - .mf => |nw| try dwarf.addrSym(nw, si, 0), + .mf => |nw| try dwarf.addrSym(nw, sym.si, sym.offset), } }, .deref => |addr| { @@ -479,6 +514,14 @@ pub const Loc = union(enum) { } try w.writeSleb128(implicit_pointer.offset); }, + .addrx_sym => |si| { + try w.writeByte(DW.OP.addrx); + try dwarf.addrxSym(w, si); + }, + .constx_sym => |si| { + try w.writeByte(DW.OP.constx); + try dwarf.addrxSym(w, si); + }, .wasm_ext => |wasm_ext| { try w.writeByte(DW.OP.WASM_location); switch (wasm_ext) { @@ -731,14 +774,16 @@ pub const WipFunc = struct { .@"extern", .@"export" => nav.name, }.toSlice(ip)); try dwarf.refType(pt, di_nw, .fromInterned(func_type.return_type)); - try dwarf.addrSym(di_nw, debug.wip_func.func_si, 0); + try dwarf.addrxSym(di_w, debug.wip_func.func_si); debug.info_func_length_offset = di_w.end; try di_w.writeInt(u32, undefined, dwarf.endian); try di_w.writeUleb128( target_info.minFunctionAlignment(target).max(nav.resolved.?.@"align").toByteUnits().?, ); - try di_w.writeByte(@intFromBool(decl.linkage != .normal)); - try di_w.writeByte(@intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu))); + try di_w.writeAll(&.{ + @intFromBool(decl.linkage != .normal), + @intFromBool(Type.fromInterned(func_type.return_type).isNoReturn(zcu)), + }); } pub fn startDebugLine(debug: *Debug) link.Error!void { @@ -1284,6 +1329,11 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { .end = 0, .set = .empty, }, + .debug_addr = .{ + .ni = .none, + .pending_index = 0, + .map = .empty, + }, .frame = .{ .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: { dev.checkAny(&.{ .llvm_backend, .x86_64_backend }); @@ -1353,6 +1403,7 @@ pub fn deinit(dwarf: *Dwarf) void { dwarf.globals.deinit(gpa); dwarf.funcs.deinit(gpa); dwarf.decls.deinit(gpa); + dwarf.debug_addr.map.deinit(gpa); dwarf.debug_line_str.map.deinit(gpa); dwarf.debug_str.map.deinit(gpa); dwarf.debug_str_offsets.map.deinit(gpa); @@ -1620,6 +1671,24 @@ pub fn genUnitPadding(dwarf: *Dwarf, w: *std.Io.Writer) std.Io.Writer.Error!void try w.writeInt(u16, 0, dwarf.endian); } +pub fn genDebugAddrHeader(dwarf: *Dwarf, dah_w: *std.Io.Writer) std.Io.Writer.Error!void { + try dwarf.genUnitLength(dah_w); + try dah_w.writeInt(u16, 5, dwarf.endian); + try dah_w.writeAll(&.{ @backingInt(dwarf.address_size), 0 }); + assert(dah_w.end == Addr.tableOffset(dwarf)); +} + +pub fn genPendingDebugAddr(dwarf: *Dwarf, da_nw: *link.MappedFile.Node.Writer) link.Error!void { + da_nw.interface.end = dwarf.debug_addr.size(dwarf); + for (dwarf.debug_addr.map.keys()[dwarf.debug_addr.pending_index..]) |si| { + dwarf.addrSym(da_nw, si, 0) catch |err| switch (err) { + else => |e| return e, + error.WriteFailed => return dwarf.reportWriteError(da_nw), + }; + dwarf.debug_addr.pending_index += 1; + } +} + pub const EhFrameHdr = extern struct { version: u8, eh_frame_ptr_enc: std.dwarf.EH.PE, @@ -1675,11 +1744,7 @@ pub fn genDebugFrameCie( const Register = @import("../codegen/x86_64/bits.zig").Register; switch (format) { .eh_frame => try df_w.writeAll("zR\x00"), - .debug_frame => { - try df_w.writeAll("\x00"); - try df_w.writeByte(@backingInt(dwarf.address_size)); - try df_w.writeByte(0); - }, + .debug_frame => try df_w.writeAll("\x00" ++ .{ @backingInt(dwarf.address_size), 0 }), } try df_w.writeUleb128(dwarf.frame.header.code_alignment_factor); try df_w.writeSleb128(dwarf.frame.header.data_alignment_factor); @@ -1726,8 +1791,7 @@ pub fn genDebugInfoHeader( if (!unit.alive) return dwarf.genUnitPadding(dih_w); try dwarf.genUnitLength(dih_w); try dih_w.writeInt(u16, 5, dwarf.endian); - try dih_w.writeByte(DW.UT.compile); - try dih_w.writeByte(@backingInt(dwarf.address_size)); + try dih_w.writeAll(&.{ DW.UT.compile, @backingInt(dwarf.address_size) }); try dwarf.secOffset(dih_nw, dwarf.debug_abbrev.ni.unwrap().?, 0); const compile_unit_offset = dih_w.end; try dwarf.abbrevCode(dih_nw, .compile_unit); @@ -1738,6 +1802,7 @@ pub fn genDebugInfoHeader( compile_unit_offset, ); try dwarf.secOffset(dih_nw, unit.debug_line_header_ni.unwrap().?, 0); + try dwarf.secOffset(dih_nw, dwarf.debug_addr.ni.unwrap().?, Addr.tableOffset(dwarf)); try dwarf.secOffset(dih_nw, unit.debug_rnglists_ni.unwrap().?, Rnglists.tableOffset(dwarf)); try dwarf.secOffset(dih_nw, dwarf.debug_str_offsets.ni.unwrap().?, StrOffsets.tableOffset(dwarf)); try dwarf.strx1(dih_nw, "zig " ++ @import("build_options").version); @@ -1818,8 +1883,7 @@ pub fn genDebugLineHeader( const dlh_w = &dlh_nw.interface; try dwarf.genUnitLength(dlh_w); try dlh_w.writeInt(u16, 5, dwarf.endian); - try dlh_w.writeByte(@backingInt(dwarf.address_size)); - try dlh_w.writeByte(0); + try dlh_w.writeAll(&.{ @backingInt(dwarf.address_size), 0 }); const header_length_offset = dlh_w.end; switch (dwarf.format) { .@"32" => try dlh_w.writeInt(u32, undefined, dwarf.endian), @@ -1950,8 +2014,7 @@ pub fn genDebugRnglistsHeader( const drh_w = &drh_nw.interface; try dwarf.genUnitLength(drh_w); try drh_w.writeInt(u16, 5, dwarf.endian); - try drh_w.writeByte(@backingInt(dwarf.address_size)); - try drh_w.writeByte(0); + try drh_w.writeAll(&.{ @backingInt(dwarf.address_size), 0 }); try drh_w.writeInt(u32, 1, dwarf.endian); assert(drh_w.end == Rnglists.tableOffset(dwarf)); switch (dwarf.format) { @@ -1971,8 +2034,8 @@ pub fn genDebugRnglistsRange( ) link.EmitError!void { const dr_w = &dr_nw.interface; dr_w.end = unit.debug_rnglists_end; - try dr_w.writeByte(DW.RLE.start_length); - try dwarf.addrSym(dr_nw, func_si, 0); + try dr_w.writeByte(DW.RLE.startx_length); + try dwarf.addrxSym(dr_w, func_si); try dr_w.writeUleb128(func_length); unit.debug_rnglists_end = dr_w.end; try dr_w.writeByte(DW.RLE.end_of_list); @@ -1986,9 +2049,10 @@ pub fn genDebugStrOffsetsHeader(dwarf: *Dwarf, dsoh_w: *std.Io.Writer) std.Io.Wr } pub fn genPendingDebugStrOffsets(dwarf: *Dwarf, dso_nw: *link.MappedFile.Node.Writer) link.Error!void { + const debug_str_ni = dwarf.debug_str.ni.unwrap().?; dso_nw.interface.end = dwarf.debug_str_offsets.size(dwarf); for (dwarf.debug_str_offsets.map.keys()[dwarf.debug_str_offsets.pending_index..]) |offset| { - dwarf.secOffset(dso_nw, dwarf.debug_str.ni.unwrap().?, offset) catch |err| switch (err) { + dwarf.secOffset(dso_nw, debug_str_ni, offset) catch |err| switch (err) { else => |e| return e, error.WriteFailed => return dwarf.reportWriteError(dso_nw), }; @@ -2081,7 +2145,7 @@ fn updateExternInner( if (func_type.is_var_args) try dwarf.abbrevCode(di_nw, .is_var_args); if (!is_empty) try di_w.writeUleb128(@backingInt(AbbrevCode.null)); } else { - const addr: Loc = .{ .addr_reloc = si }; + const addr: Loc = .{ .addr_sym = .{ .si = si } }; const loc: Loc = if (nav_threadlocal) switch (arch) { .x86_64 => .{ .form_tls_address = &addr }, else => unreachable, @@ -2169,7 +2233,7 @@ fn updateGlobalInner( .@"extern" => unreachable, .@"export" => nav.name, }.toSlice(ip)); - const addr: Loc = .{ .addr_reloc = si }; + const addr: Loc = .{ .addr_sym = .{ .si = si } }; const loc: Loc = if (nav_threadlocal) switch (arch) { .x86_64 => .{ .form_tls_address = &addr }, else => unreachable, @@ -4403,6 +4467,21 @@ fn addrSym( .absAddr(elf), ) else unreachable; } +fn addrxSym(dwarf: *Dwarf, w: *std.Io.Writer, si: link.File.SymbolId) link.EmitError!void { + try w.writeUleb128(try dwarf.debug_addr.get(dwarf.lf.comp.gpa, si)); +} +fn addrx1Sym(dwarf: *Dwarf, w: *std.Io.Writer, si: link.File.SymbolId) link.EmitError!void { + try w.writeByte(@intCast(try dwarf.debug_addr.get(dwarf.lf.comp.gpa, si))); +} +fn addrx2Sym(dwarf: *Dwarf, w: *std.Io.Writer, si: link.File.SymbolId) link.EmitError!void { + try w.writeInt(u16, @intCast(try dwarf.debug_addr.get(dwarf.lf.comp.gpa, si)), dwarf.endian); +} +fn addrx3Sym(dwarf: *Dwarf, w: *std.Io.Writer, si: link.File.SymbolId) link.EmitError!void { + try w.writeInt(u24, @intCast(try dwarf.debug_addr.get(dwarf.lf.comp.gpa, si)), dwarf.endian); +} +fn addrx4Sym(dwarf: *Dwarf, w: *std.Io.Writer, si: link.File.SymbolId) link.EmitError!void { + try w.writeInt(u32, @intCast(try dwarf.debug_addr.get(dwarf.lf.comp.gpa, si)), dwarf.endian); +} fn blockConst( dwarf: *Dwarf, @@ -5072,7 +5151,7 @@ pub const AbbrevCode = enum { .attrs = decl_attrs ++ .{ .{ .linkage_name, .strx }, .{ .type, .ref_addr }, - .{ .low_pc, .addr }, + .{ .low_pc, .addrx }, .{ .high_pc, .data4 }, .{ .alignment, .udata }, .{ .external, .flag }, @@ -5085,7 +5164,7 @@ pub const AbbrevCode = enum { .attrs = decl_attrs ++ .{ .{ .linkage_name, .strx }, .{ .type, .ref_addr }, - .{ .low_pc, .addr }, + .{ .low_pc, .addrx }, .{ .high_pc, .data4 }, .{ .alignment, .udata }, .{ .external, .flag }, @@ -5353,7 +5432,7 @@ pub const AbbrevCode = enum { .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strx }, .{ .type, .ref_addr }, - .{ .low_pc, .addr }, + .{ .low_pc, .addrx }, .{ .high_pc, .data4 }, .{ .alignment, .udata }, .{ .external, .flag }, @@ -5366,7 +5445,7 @@ pub const AbbrevCode = enum { .attrs = decl_instance_attrs ++ .{ .{ .linkage_name, .strx }, .{ .type, .ref_addr }, - .{ .low_pc, .addr }, + .{ .low_pc, .addrx }, .{ .high_pc, .data4 }, .{ .alignment, .udata }, .{ .external, .flag }, @@ -6020,6 +6099,7 @@ pub const AbbrevCode = enum { .{ .language, .data1 }, .{ .base_types, .ref_addr }, .{ .stmt_list, .sec_offset }, + .{ .addr_base, .sec_offset }, .{ .rnglists_base, .sec_offset }, .{ .str_offsets_base, .sec_offset }, .{ .producer, .strx1 }, diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 4a99282344b85bc3837002e77d35633ff875d5e7..6a9f53ff5b7d6247733946d5055f8733d8f0dca5 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -53,6 +53,7 @@ shndx: struct { rela_dyn: Section.Index, rela_plt: Section.Index, debug_abbrev: Section.Index, + debug_addr: Section.Index, eh_frame_hdr: Section.Index, eh_frame: Section.Index, debug_frame: Section.Index, @@ -215,6 +216,7 @@ textrel_count: u32, dwarf: Dwarf, dwarf_shared: std.enums.EnumArray(Dwarf.SharedSection, dwarf_relocs.Shared), +dwarf_addr: dwarf_relocs.Addr, dwarf_str_offsets: dwarf_relocs.StrOffsets, dwarf_units: []dwarf_relocs.Unit, dwarf_consts: std.array_hash_map.Auto(link.ConstPool.Index, dwarf_relocs.Const), @@ -287,6 +289,7 @@ const Node = union(enum) { lazy_const_data: LazyMapRef.Index(.const_data), debug_shared: Dwarf.SharedSection, + debug_addr, eh_frame_footer, debug_str_offsets, unit_padding, @@ -882,6 +885,10 @@ const dwarf_relocs = struct { const Shared = struct { first_target_reloc: NodeReloc.Index, }; + const Addr = struct { + first_target_reloc: NodeReloc.Index, + symbol_relocs: std.ArrayList(SymbolReloc.Index), + }; const StrOffsets = struct { first_target_reloc: NodeReloc.Index, node_relocs: std.ArrayList(NodeReloc.Index), @@ -3352,6 +3359,7 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { .input_section, .copied_global, .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -3807,6 +3815,7 @@ fn create( .rela_dyn = .UNDEF, .rela_plt = .UNDEF, .debug_abbrev = .UNDEF, + .debug_addr = .UNDEF, .eh_frame_hdr = .UNDEF, .eh_frame = .UNDEF, .debug_frame = .UNDEF, @@ -3873,6 +3882,10 @@ fn create( .dwarf_shared = comptime .initFill(.{ .first_target_reloc = .none, }), + .dwarf_addr = .{ + .first_target_reloc = .none, + .symbol_relocs = .empty, + }, .dwarf_str_offsets = .{ .first_target_reloc = .none, .node_relocs = .empty, @@ -3932,6 +3945,7 @@ pub fn deinit(elf: *Elf) void { elf.changed_symtab_index.deinit(gpa); elf.dwarf.deinit(); + elf.dwarf_addr.symbol_relocs.deinit(gpa); elf.dwarf_str_offsets.node_relocs.deinit(gpa); for (elf.dwarf_units) |*dwarf_unit| dwarf_unit.debug_rnglists_symbol_relocs.deinit(gpa); gpa.free(elf.dwarf_units); @@ -4012,6 +4026,7 @@ fn initHeaders( .strip => {}, .dwarf => { shnum += 1; // .debug_abbrev + shnum += 1; // .debug_addr shnum += @intFromBool(have_debug_frame); // .debug_frame shnum += 1; // .debug_info shnum += 1; // .debug_line @@ -5116,6 +5131,11 @@ fn initHeaders( .strip => {}, .dwarf => { elf.shndx.debug_abbrev = try elf.addSection(elf.ni.elf, .{ .name = ".debug_abbrev" }); + elf.shndx.debug_addr = try elf.addSection(elf.ni.elf, .{ + .name = ".debug_addr", + .addralign = addr_align, + .node_align = elf.mf.flags.block_size, + }); if (have_debug_frame) elf.shndx.debug_frame = try elf.addSection(elf.ni.elf, .{ .name = ".debug_frame", .addralign = addr_align, @@ -5144,7 +5164,10 @@ fn initHeaders( }); elf.shndx.debug_str_offsets = try elf.addSection(elf.ni.elf, .{ .name = ".debug_str_offsets", - .addralign = addr_align, + .addralign = switch (elf.dwarf.format) { + .@"32" => .@"4", + .@"64" => .@"8", + }, .node_align = elf.mf.flags.block_size, }); }, @@ -5240,6 +5263,7 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { .lazy_code, .lazy_const_data, .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -5288,6 +5312,7 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { .lazy_const_data, => |i| Symbol.Id.local(i.symbol(elf)).value(elf), .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -5329,7 +5354,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { .lazy_code, .lazy_const_data, => |i| Symbol.Id.local(i.symbol(elf)).value(elf), - .debug_shared, .eh_frame_footer, .debug_str_offsets, .unit_padding => unreachable, + .debug_shared, .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding => unreachable, .unit_frame, .unit_debug_info, .unit_debug_line => { const section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); break :parent_vaddr elf.getNodeShndx(parent_ni).vaddr(elf) + section_offset; @@ -5366,7 +5391,7 @@ fn computeNodeSectionOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { .section, .section_manual_size => 0, .input_section, .copied_global => unreachable, .nav, .uav, .lazy_code, .lazy_const_data => unreachable, - .debug_shared, .eh_frame_footer, .debug_str_offsets, .unit_padding => unreachable, + .debug_shared, .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding => unreachable, .unit_frame, .unit_debug_info, .unit_debug_line => { const parent_section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); break :parent_section_offset parent_section_offset; @@ -5415,6 +5440,7 @@ pub fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { .segment, .copied_global, .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -7215,8 +7241,14 @@ fn prelinkInner(elf: *Elf) Error!void { }; elf.input_pending_index += 1; - try elf.nodes.ensureUnusedCapacity(gpa, 6 + 4); - for ([6]Section.Index{ + const addr_align: Alignment = switch (elf.identClass()) { + .NONE, _ => unreachable, + .@"32" => .@"4", + .@"64" => .@"8", + }; + try elf.nodes.ensureUnusedCapacity(gpa, 7 + 5); + for ([7]Section.Index{ + elf.shndx.debug_addr, elf.shndx.eh_frame, elf.shndx.debug_frame, elf.shndx.debug_info, @@ -7238,11 +7270,7 @@ fn prelinkInner(elf: *Elf) Error!void { }; break :last_header_oni last_header_oni; }, .{ - .alignment = if (frame_format) |_| switch (elf.identClass()) { - .NONE, _ => unreachable, - .@"32" => .@"4", - .@"64" => .@"8", - } else .@"1", + .alignment = if (frame_format) |_| addr_align else .@"1", .next_moved = true, .enable_next_moved = true, }), @@ -7258,6 +7286,28 @@ fn prelinkInner(elf: *Elf) Error!void { error.WriteFailed => return debug_nw.err.?, }; } + switch (elf.shndx.debug_addr) { + .UNDEF => {}, + else => |debug_addr_shndx| { + const debug_addr_ni = elf.addNodeAssumeCapacity( + try debug_addr_shndx.get(elf).ni.addFloatingChild(gpa, &elf.mf, .{ + .alignment = addr_align, + .next_moved = true, + .enable_next_moved = true, + }), + .debug_addr, + ); + elf.dwarf.debug_addr.ni = .wrap(debug_addr_ni); + + var dah_nw: link.MappedFile.Node.Writer = undefined; + debug_addr_ni.writer(gpa, &elf.mf, &dah_nw); + defer dah_nw.deinit(); + elf.dwarf.genDebugAddrHeader(&dah_nw.interface) catch |err| switch (err) { + else => |e| return e, + error.WriteFailed => return dah_nw.err.?, + }; + }, + } switch (elf.shndx.debug_abbrev) { .UNDEF => {}, else => |debug_abbrev_shndx| elf.dwarf.debug_abbrev.ni = .wrap(elf.addNodeAssumeCapacity( @@ -7430,7 +7480,7 @@ fn zcuFilesReadyInner(elf: *Elf, zcu: *Zcu) Error!void { error.WriteFailed => return dih_nw.err.?, }; } - try elf.genPendingDebugStrings(gpa); + try elf.genPendingDebug(gpa); } fn flushFiles(elf: *Elf) Error!void { @@ -8255,6 +8305,7 @@ fn addNodeRelocAssumeCapacity( const first_target_reloc = switch (elf.getNode(target)) { else => unreachable, .debug_shared => |ss| &elf.dwarf_shared.getPtr(ss).first_target_reloc, + .debug_addr => &elf.dwarf_addr.first_target_reloc, .debug_str_offsets => &elf.dwarf_str_offsets.first_target_reloc, .unit_frame_cie => |ui| &elf.dwarf_units[@backingInt(ui)].frame_cie_first_target_reloc, .unit_debug_info_header => |ui| &elf.dwarf_units[@backingInt(ui)].debug_info_header_first_target_reloc, @@ -8361,6 +8412,7 @@ fn addGotRelocAssumeCapacity( .segment, .copied_global, .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -9211,7 +9263,8 @@ fn flushInner( assert(elf.input_section_pending_index == elf.input_sections.items.len); assert(elf.pending_uavs.items.len == 0); assert(elf.dwarf.const_pool.pending.items.len == 0); - assert(elf.dwarf.debug_str_offsets.pending_index == elf.dwarf.debug_str_offsets.map.count()); + assert(!elf.dwarf.debug_addr.anyPending()); + assert(!elf.dwarf.debug_str_offsets.anyPending()); // We've done the final `idle` loop, so everything is at its final place in the file. We have a // few more things to check and write now that addresses and offsets are finalized. @@ -9536,9 +9589,22 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) link.Error!void { }, .code_view => unreachable, } - try elf.genPendingDebugStrings(gpa); + try elf.genPendingDebug(gpa); } -fn genPendingDebugStrings(elf: *Elf, gpa: std.mem.Allocator) link.Error!void { +fn genPendingDebug(elf: *Elf, gpa: std.mem.Allocator) link.Error!void { + while (elf.dwarf.debug_addr.map.count() - elf.dwarf.debug_addr.pending_index > 0) { + const debug_addr_ni = elf.dwarf.debug_addr.ni.unwrap().?; + try debug_addr_ni.moved(gpa, &elf.mf); + var da_nw: link.MappedFile.Node.Writer = undefined; + debug_addr_ni.writer(gpa, &elf.mf, &da_nw); + defer da_nw.deinit(); + const first_symbol_ri = elf.symbol_relocs.items.len; + try elf.dwarf.genPendingDebugAddr(&da_nw); + const symbol_relocs = &elf.dwarf_addr.symbol_relocs; + try symbol_relocs.ensureUnusedCapacity(gpa, elf.symbol_relocs.items.len - first_symbol_ri); + for (first_symbol_ri..elf.symbol_relocs.items.len) |symbol_ri| + symbol_relocs.appendAssumeCapacity(@fromBackingInt(@intCast(symbol_ri))); + } while (elf.dwarf.debug_str_offsets.map.count() - elf.dwarf.debug_str_offsets.pending_index > 0) { const debug_str_offsets_ni = elf.dwarf.debug_str_offsets.ni.unwrap().?; try debug_str_offsets_ni.moved(gpa, &elf.mf); @@ -9958,6 +10024,22 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void .unit_debug_info, .unit_debug_line, => {}, + .debug_addr => { + const target_section_offset = elf.computeNodeSectionOffset(ni); + var target_ri = elf.dwarf_addr.first_target_reloc; + while (target_ri != .none) { + const target_reloc = target_ri.get(elf); + assert(target_reloc.target == ni); + target_reloc.flushMovedTarget(elf, target_section_offset); + target_ri = target_reloc.next; + } + const node_vaddr = elf.computeNodeVAddr(ni); + for (elf.dwarf_addr.symbol_relocs.items) |symbol_ri| { + const symbol_reloc = symbol_ri.get(elf); + assert(symbol_reloc.node.unwrap().? == ni); + symbol_reloc.flushMovedNode(elf, node_vaddr); + } + }, .debug_str_offsets => { const target_section_offset = elf.computeNodeSectionOffset(ni); var target_ri = elf.dwarf_str_offsets.first_target_reloc; @@ -10356,6 +10438,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo .lazy_code, .lazy_const_data, .debug_shared, + .debug_addr, .eh_frame_footer, .debug_str_offsets, .unit_padding, @@ -10430,6 +10513,7 @@ fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo error.NoSpaceLeft => archive.strtab_member_too_big = true, } }, + .debug_addr, .debug_str_offsets, .unit_padding, .unit_frame_cie, @@ -10447,6 +10531,7 @@ fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo const offset, const size = ni.location(&elf.mf).resolve(&elf.mf); break :location .{ offset, switch (node) { else => unreachable, + .debug_addr => elf.dwarf.debug_addr.size(&elf.dwarf), .debug_str_offsets => elf.dwarf.debug_str_offsets.size(&elf.dwarf), .unit_padding, .unit_frame_cie, @@ -10475,7 +10560,7 @@ fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo }; switch (node) { else => unreachable, - .debug_str_offsets, .unit_padding, .unit_debug_rnglists => { + .debug_addr, .debug_str_offsets, .unit_padding, .unit_debug_rnglists => { const parent_slice = parent_ni.slicePadding(&elf.mf); const frame_shndx = elf.getNodeShndx(parent_ni); const frame_format = frame_shndx.debugFrameFormat(elf) orelse @@ -10600,13 +10685,13 @@ fn flushPadding(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo var fw: Io.Writer = .fixed(slice[@intCast(size)..]); switch (node) { else => unreachable, - .debug_str_offsets, .unit_debug_rnglists => { + .debug_addr, .debug_str_offsets, .unit_debug_rnglists => { elf.dwarf.genUnitPadding(&fw) catch |err| switch (err) { error.WriteFailed => { elf.dwarf.updateUnitLength(slice, slice.len); @memset(fw.buffer, switch (node) { else => unreachable, - .debug_str_offsets => std.math.maxInt(u8), + .debug_addr, .debug_str_offsets => std.math.maxInt(u8), .unit_debug_rnglists => std.dwarf.RLE.end_of_list, }); return; -- 2.54.0