aboutsummaryrefslogtreecommitdiff
path: root/src/link/Elf
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2024-08-26 15:38:35 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2024-08-27 03:55:56 -0400
commitf289b82d0efda77b72ccf9c826023e904f9ffcab (patch)
treeeb0bbade490e385b46942628016d34dd32515c86 /src/link/Elf
parent26d4fd5276eaaa939cf21a516265101c551b62f2 (diff)
downloadzig-f289b82d0efda77b72ccf9c826023e904f9ffcab.tar.gz
zig-f289b82d0efda77b72ccf9c826023e904f9ffcab.zip
Dwarf: implement .eh_frame
Diffstat (limited to 'src/link/Elf')
-rw-r--r--src/link/Elf/ZigObject.zig51
-rw-r--r--src/link/Elf/relocatable.zig42
-rw-r--r--src/link/Elf/relocation.zig27
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"),
};
}