diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-26 15:38:35 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2024-08-27 03:55:56 -0400 |
| commit | f289b82d0efda77b72ccf9c826023e904f9ffcab (patch) | |
| tree | eb0bbade490e385b46942628016d34dd32515c86 /src/link/Elf | |
| parent | 26d4fd5276eaaa939cf21a516265101c551b62f2 (diff) | |
| download | zig-f289b82d0efda77b72ccf9c826023e904f9ffcab.tar.gz zig-f289b82d0efda77b72ccf9c826023e904f9ffcab.zip | |
Dwarf: implement .eh_frame
Diffstat (limited to 'src/link/Elf')
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 51 | ||||
| -rw-r--r-- | src/link/Elf/relocatable.zig | 42 | ||||
| -rw-r--r-- | src/link/Elf/relocation.zig | 27 |
3 files changed, 86 insertions, 34 deletions
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index acee16673e..df811dcfb0 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -49,6 +49,7 @@ debug_line_section_dirty: bool = false, debug_line_str_section_dirty: bool = false, debug_loclists_section_dirty: bool = false, debug_rnglists_section_dirty: bool = false, +eh_frame_section_dirty: bool = false, debug_info_index: ?Symbol.Index = null, debug_abbrev_index: ?Symbol.Index = null, @@ -58,6 +59,7 @@ debug_line_index: ?Symbol.Index = null, debug_line_str_index: ?Symbol.Index = null, debug_loclists_index: ?Symbol.Index = null, debug_rnglists_index: ?Symbol.Index = null, +eh_frame_index: ?Symbol.Index = null, pub const global_symbol_bit: u32 = 0x80000000; pub const symbol_mask: u32 = 0x7fffffff; @@ -72,8 +74,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { const comp = elf_file.base.comp; const gpa = comp.gpa; const ptr_size = elf_file.ptrWidthBytes(); - const target = elf_file.getTarget(); - const ptr_bit_width = target.ptrBitWidth(); try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section try self.relocs.append(gpa, .{}); // null relocs section @@ -113,7 +113,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .type = elf.PT_LOAD, .offset = off, .filesz = filesz, - .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, + .addr = if (ptr_size >= 4) 0x4000000 else 0x4000, .memsz = filesz, .@"align" = elf_file.page_size, .flags = elf.PF_X | elf.PF_R | elf.PF_W, @@ -128,7 +128,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .type = elf.PT_LOAD, .offset = off, .filesz = filesz, - .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000, + .addr = if (ptr_size >= 4) 0xc000000 else 0xa000, .memsz = filesz, .@"align" = alignment, .flags = elf.PF_R | elf.PF_W, @@ -143,7 +143,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { .type = elf.PT_LOAD, .offset = off, .filesz = filesz, - .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000, + .addr = if (ptr_size >= 4) 0x10000000 else 0xc000, .memsz = filesz, .@"align" = alignment, .flags = elf.PF_R | elf.PF_W, @@ -154,7 +154,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { const alignment = elf_file.page_size; elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{ .type = elf.PT_LOAD, - .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000, + .addr = if (ptr_size >= 4) 0x14000000 else 0xf000, .memsz = 1024, .@"align" = alignment, .flags = elf.PF_R | elf.PF_W, @@ -354,6 +354,20 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); } + if (elf_file.eh_frame_section_index == null) { + elf_file.eh_frame_section_index = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".eh_frame"), + .type = if (elf_file.getTarget().cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = ptr_size, + }); + self.eh_frame_section_dirty = true; + self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?); + } + try dwarf.initMetadata(); self.dwarf = dwarf; }, @@ -460,6 +474,7 @@ 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.?, + self.eh_frame_index.?, }, [_]*Dwarf.Section{ &dwarf.debug_info.section, &dwarf.debug_abbrev.section, @@ -469,7 +484,18 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi &dwarf.debug_line_str.section, &dwarf.debug_loclists.section, &dwarf.debug_rnglists.section, - }) |sym_index, sect| { + &dwarf.debug_frame.section, + }, [_]Dwarf.Section.Index{ + .debug_info, + .debug_abbrev, + .debug_str, + .debug_aranges, + .debug_line, + .debug_line_str, + .debug_loclists, + .debug_rnglists, + .debug_frame, + }) |sym_index, sect, sect_index| { const sym = self.symbol(sym_index); const atom_ptr = self.atom(sym.ref.index).?; if (!atom_ptr.alive) continue; @@ -509,6 +535,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi for (unit.cross_section_relocs.items) |reloc| { const target_sym_index = switch (reloc.target_sec) { .debug_abbrev => self.debug_abbrev_index.?, + .debug_aranges => self.debug_aranges_index.?, + .debug_frame => self.eh_frame_index.?, .debug_info => self.debug_info_index.?, .debug_line => self.debug_line_index.?, .debug_line_str => self.debug_line_str_index.?, @@ -547,7 +575,10 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi entry.external_relocs.items.len); for (entry.cross_entry_relocs.items) |reloc| { const r_offset = entry_off + reloc.source_off; - const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off); + const r_addend: i64 = @intCast(unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry| + unit.header_len + unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off + else + 0)); const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch); log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ self.symbol(sym_index).name(elf_file), @@ -584,6 +615,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi for (entry.cross_section_relocs.items) |reloc| { const target_sym_index = switch (reloc.target_sec) { .debug_abbrev => self.debug_abbrev_index.?, + .debug_aranges => self.debug_aranges_index.?, + .debug_frame => self.eh_frame_index.?, .debug_info => self.debug_info_index.?, .debug_line => self.debug_line_index.?, .debug_line_str => self.debug_line_str_index.?, @@ -617,7 +650,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi const target_sym = self.symbol(reloc.target_sym); const r_offset = entry_off + reloc.source_off; const r_addend: i64 = @intCast(reloc.target_off); - const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch); + const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch); log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ target_sym.name(elf_file), r_offset, diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index 58610fd3c3..8f5ea8e25b 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -289,8 +289,6 @@ fn claimUnresolved(elf_file: *Elf) void { } fn initSections(elf_file: *Elf) !void { - const ptr_size = elf_file.ptrWidthBytes(); - for (elf_file.objects.items) |index| { const object = elf_file.file(index).?.object; try object.initOutputSections(elf_file); @@ -306,13 +304,18 @@ fn initSections(elf_file: *Elf) !void { if (elf_file.file(index).?.object.cies.items.len > 0) break true; } else false; if (needs_eh_frame) { - elf_file.eh_frame_section_index = try elf_file.addSection(.{ - .name = try elf_file.insertShString(".eh_frame"), - .type = elf.SHT_PROGBITS, - .flags = elf.SHF_ALLOC, - .addralign = ptr_size, - .offset = std.math.maxInt(u64), - }); + if (elf_file.eh_frame_section_index == null) { + elf_file.eh_frame_section_index = try elf_file.addSection(.{ + .name = try elf_file.insertShString(".eh_frame"), + .type = if (elf_file.getTarget().cpu.arch == .x86_64) + elf.SHT_X86_64_UNWIND + else + elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC, + .addralign = elf_file.ptrWidthBytes(), + .offset = std.math.maxInt(u64), + }); + } elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr( try elf_file.insertShString(".rela.eh_frame"), elf_file.eh_frame_section_index.?, @@ -373,7 +376,11 @@ fn updateSectionSizes(elf_file: *Elf) !void { } if (elf_file.eh_frame_section_index) |index| { - slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file); + slice.items(.shdr)[index].sh_size = existing_size: { + const zo = elf_file.zigObjectPtr() orelse break :existing_size 0; + const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); + break :existing_size sym.atom(elf_file).?.size; + } + try eh_frame.calcEhFrameSize(elf_file); } if (elf_file.eh_frame_rela_section_index) |index| { const shdr = &slice.items(.shdr)[index]; @@ -526,17 +533,22 @@ fn writeSyntheticSections(elf_file: *Elf) !void { } if (elf_file.eh_frame_section_index) |shndx| { + const existing_size = existing_size: { + const zo = elf_file.zigObjectPtr() orelse break :existing_size 0; + const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); + break :existing_size sym.atom(elf_file).?.size; + }; const shdr = slice.items(.shdr)[shndx]; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; - var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); + var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size)); defer buffer.deinit(); try eh_frame.writeEhFrameObject(elf_file, buffer.writer()); log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ - shdr.sh_offset, - shdr.sh_offset + shdr.sh_size, + shdr.sh_offset + existing_size, + shdr.sh_offset + sh_size, }); - assert(buffer.items.len == sh_size); - try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); + assert(buffer.items.len == sh_size - existing_size); + try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size); } if (elf_file.eh_frame_rela_section_index) |shndx| { const shdr = slice.items(.shdr)[shndx]; diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig index d6f8dc5d10..047312cd68 100644 --- a/src/link/Elf/relocation.zig +++ b/src/link/Elf/relocation.zig @@ -108,20 +108,27 @@ pub const dwarf = struct { pub fn externalRelocType( target: Symbol, + source_section: Dwarf.Section.Index, address_size: Dwarf.AddressSize, cpu_arch: std.Target.Cpu.Arch, ) u32 { return switch (cpu_arch) { - .x86_64 => @intFromEnum(switch (address_size) { - .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32", - .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64", - else => unreachable, - }), - .riscv64 => @intFromEnum(switch (address_size) { - .@"32" => elf.R_RISCV.@"32", - .@"64" => elf.R_RISCV.@"64", - else => unreachable, - }), + .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) { + else => switch (address_size) { + .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32", + .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64", + else => unreachable, + }, + .debug_frame => .PC32, + })), + .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) { + else => switch (address_size) { + .@"32" => .@"32", + .@"64" => .@"64", + else => unreachable, + }, + .debug_frame => unreachable, + })), else => @panic("TODO unhandled cpu arch"), }; } |
