From d388d555d5abc06962e4e8a409a5fa28f8c4f84c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Mon, 19 Aug 2024 08:40:22 +0200 Subject: [PATCH] elf: parse and emit Elf relocs for cross section refs for .debug* sections --- src/link/Dwarf.zig | 8 ++--- src/link/Elf/ZigObject.zig | 65 +++++++++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index a6b73421ba..b602c2a2da 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -287,7 +287,7 @@ pub const Section = struct { return sec.getUnit(unit).addEntry(sec, dwarf); } - fn getUnit(sec: *Section, unit: Unit.Index) *Unit { + pub fn getUnit(sec: *Section, unit: Unit.Index) *Unit { return &sec.units.items[@intFromEnum(unit)]; } @@ -368,7 +368,7 @@ const Unit = struct { none = std.math.maxInt(u32), _, - fn unwrap(uio: Optional) ?Index { + pub fn unwrap(uio: Optional) ?Index { return if (uio != .none) @enumFromInt(@intFromEnum(uio)) else null; } }; @@ -614,7 +614,7 @@ const Entry = struct { none = std.math.maxInt(u32), _, - fn unwrap(eio: Optional) ?Index { + pub fn unwrap(eio: Optional) ?Index { return if (eio != .none) @enumFromInt(@intFromEnum(eio)) else null; } }; @@ -736,7 +736,7 @@ const Entry = struct { } } - fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry { + pub fn assertNonEmpty(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) *Entry { if (entry.len > 0) return entry; if (std.debug.runtime_safety) { log.err("missing {} from {s}", .{ diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 18eb047b0b..3cb686e0ca 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -195,15 +195,15 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi self.debug_line_str_index.?, self.debug_loclists_index.?, self.debug_rnglists_index.?, - }, [_]Dwarf.Section{ - dwarf.debug_info.section, - dwarf.debug_abbrev.section, - dwarf.debug_str.section, - dwarf.debug_aranges.section, - dwarf.debug_line.section, - dwarf.debug_line_str.section, - dwarf.debug_loclists.section, - dwarf.debug_rnglists.section, + }, [_]*Dwarf.Section{ + &dwarf.debug_info.section, + &dwarf.debug_abbrev.section, + &dwarf.debug_str.section, + &dwarf.debug_aranges.section, + &dwarf.debug_line.section, + &dwarf.debug_line_str.section, + &dwarf.debug_loclists.section, + &dwarf.debug_rnglists.section, }) |sym_index, sect| { const sym = self.symbol(sym_index); const atom_ptr = self.atom(sym.ref.index).?; @@ -215,11 +215,52 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi atom_ptr.size = shdr.sh_size; atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); + log.debug("parsing relocs in {s}", .{sym.name(elf_file)}); + const relocs = &self.relocs.items[atom_ptr.relocsShndx().?]; for (sect.units.items) |*unit| { + try relocs.ensureUnusedCapacity(gpa, unit.cross_section_relocs.items.len); + for (unit.cross_section_relocs.items) |reloc| { + const target_sym_index = switch (reloc.target_sec) { + .debug_abbrev => self.debug_abbrev_index.?, + .debug_info => self.debug_info_index.?, + .debug_line => self.debug_line_index.?, + .debug_line_str => self.debug_line_str_index.?, + .debug_loclists => self.debug_loclists_index.?, + .debug_rnglists => self.debug_rnglists_index.?, + .debug_str => self.debug_str_index.?, + }; + const target_sec = switch (reloc.target_sec) { + inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section, + }; + const target_unit = target_sec.getUnit(reloc.target_unit); + const r_offset = unit.off + reloc.source_off + (if (reloc.source_entry.unwrap()) |source_entry| + unit.header_len + unit.getEntry(source_entry).off + else + 0); + const r_addend: i64 = @intCast(reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry| + target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off + else + 0)); + const r_type: elf.R_X86_64 = switch (dwarf.format) { + .@"32" => .@"32", + .@"64" => .@"64", + }; + log.debug(" {s} <- r_off={x}, r_add={x}, r_type={s}", .{ + self.symbol(target_sym_index).name(elf_file), + r_offset, + r_addend, + @tagName(r_type), + }); + atom_ptr.addRelocAssumeCapacity(.{ + .r_offset = r_offset, + .r_addend = r_addend, + .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | @intFromEnum(r_type), + }, self); + } + try relocs.ensureUnusedCapacity(gpa, unit.external_relocs.items.len); for (unit.external_relocs.items) |reloc| { - const tsym = self.symbol(reloc.target_sym); const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off; const r_addend: i64 = @intCast(reloc.target_off); const r_type: elf.R_X86_64 = switch (dwarf.address_size) { @@ -227,8 +268,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi .@"64" => .@"64", else => unreachable, }; - log.debug("{s} <- r_off={x}, r_add={x}, r_type={s}\n", .{ - tsym.name(elf_file), + log.debug(" {s} <- r_off={x}, r_add={x}, r_type={s}", .{ + self.symbol(reloc.target_sym).name(elf_file), r_offset, r_addend, @tagName(r_type),