aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-06-25 16:36:59 +0200
committerAndrew Kelley <andrew@ziglang.org>2023-06-25 14:33:00 -0700
commit852eb272bf895ee6fc242e298e31d666caa9d0df (patch)
treecef7aa1fe4ecbe34d4e92559c1e89fa67e32fced /src/link
parentdf389b62de4430434a6518580e27208101ae2fc8 (diff)
downloadzig-852eb272bf895ee6fc242e298e31d666caa9d0df.tar.gz
zig-852eb272bf895ee6fc242e298e31d666caa9d0df.zip
macho: add fixes to __eh_frame parsing emitted by Nix C++ compiler
Diffstat (limited to 'src/link')
-rw-r--r--src/link/MachO/Object.zig6
-rw-r--r--src/link/MachO/UnwindInfo.zig2
-rw-r--r--src/link/MachO/dead_strip.zig2
-rw-r--r--src/link/MachO/eh_frame.zig33
4 files changed, 35 insertions, 8 deletions
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 29fe2988b6..3e752d4a19 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -740,7 +740,11 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
.aarch64 => {
assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed
// Find function symbol that this record describes
- const rel = relocs[rel_pos.start..][rel_pos.len - 1];
+ const rel = for (relocs[rel_pos.start..][0..rel_pos.len]) |rel| {
+ if (rel.r_address - @as(i32, @intCast(offset)) == 8 and
+ @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)) == .ARM64_RELOC_UNSIGNED)
+ break rel;
+ } else unreachable;
const target = Atom.parseRelocTarget(zld, .{
.object_id = object_id,
.rel = rel,
diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig
index cfef053d1b..7e331cae3c 100644
--- a/src/link/MachO/UnwindInfo.zig
+++ b/src/link/MachO/UnwindInfo.zig
@@ -499,7 +499,7 @@ fn collectPersonalityFromDwarf(
const fde_offset = object.eh_frame_records_lookup.get(atom_index).?;
it.seekTo(fde_offset);
const fde = (try it.next()).?;
- const cie_ptr = fde.getCiePointer();
+ const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
const cie_offset = fde_offset + 4 - cie_ptr;
it.seekTo(cie_offset);
const cie = (try it.next()).?;
diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig
index 890b40ed85..22da7a4c99 100644
--- a/src/link/MachO/dead_strip.zig
+++ b/src/link/MachO/dead_strip.zig
@@ -363,7 +363,7 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A
it.seekTo(fde_offset);
const fde = (try it.next()).?;
- const cie_ptr = fde.getCiePointer();
+ const cie_ptr = fde.getCiePointerSource(object_id, zld, fde_offset);
const cie_offset = fde_offset + 4 - cie_ptr;
it.seekTo(cie_offset);
const cie = (try it.next()).?;
diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig
index eb4419cd7b..36c8a79403 100644
--- a/src/link/MachO/eh_frame.zig
+++ b/src/link/MachO/eh_frame.zig
@@ -29,7 +29,7 @@ pub fn scanRelocs(zld: *Zld) !void {
it.seekTo(fde_offset);
const fde = (try it.next()).?;
- const cie_ptr = fde.getCiePointer();
+ const cie_ptr = fde.getCiePointerSource(@intCast(object_id), zld, fde_offset);
const cie_offset = fde_offset + 4 - cie_ptr;
if (!cies.contains(cie_offset)) {
@@ -52,7 +52,7 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
const gpa = zld.gpa;
var size: u32 = 0;
- for (zld.objects.items) |*object| {
+ for (zld.objects.items, 0..) |*object, object_id| {
var cies = std.AutoHashMap(u32, u32).init(gpa);
defer cies.deinit();
@@ -72,7 +72,7 @@ pub fn calcSectionSize(zld: *Zld, unwind_info: *const UnwindInfo) !void {
eh_it.seekTo(fde_record_offset);
const source_fde_record = (try eh_it.next()).?;
- const cie_ptr = source_fde_record.getCiePointer();
+ const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
const cie_offset = fde_record_offset + 4 - cie_ptr;
const gop = try cies.getOrPut(cie_offset);
@@ -131,7 +131,7 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
eh_it.seekTo(fde_record_offset);
const source_fde_record = (try eh_it.next()).?;
- const cie_ptr = source_fde_record.getCiePointer();
+ const cie_ptr = source_fde_record.getCiePointerSource(@intCast(object_id), zld, fde_record_offset);
const cie_offset = fde_record_offset + 4 - cie_ptr;
const gop = try cies.getOrPut(cie_offset);
@@ -150,12 +150,12 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
}
var fde_record = try source_fde_record.toOwned(gpa);
- fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*);
try fde_record.relocate(zld, @as(u32, @intCast(object_id)), .{
.source_offset = fde_record_offset,
.out_offset = eh_frame_offset,
.sect_addr = sect.addr,
});
+ fde_record.setCiePointer(eh_frame_offset + 4 - gop.value_ptr.*);
switch (cpu_arch) {
.aarch64 => {}, // relocs take care of LSDA pointers
@@ -380,6 +380,29 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
}
}
+ pub fn getCiePointerSource(rec: Record, object_id: u32, zld: *Zld, offset: u32) u32 {
+ assert(rec.tag == .fde);
+ const cpu_arch = zld.options.target.cpu.arch;
+ const addend = mem.readIntLittle(u32, rec.data[0..4]);
+ switch (cpu_arch) {
+ .aarch64 => {
+ const relocs = getRelocs(zld, object_id, offset);
+ const maybe_rel = for (relocs) |rel| {
+ if (rel.r_address - @as(i32, @intCast(offset)) == 4 and
+ @as(macho.reloc_type_arm64, @enumFromInt(rel.r_type)) == .ARM64_RELOC_SUBTRACTOR)
+ break rel;
+ } else null;
+ const rel = maybe_rel orelse return addend;
+ const object = &zld.objects.items[object_id];
+ const target_addr = object.in_symtab.?[rel.r_symbolnum].n_value;
+ const sect = object.getSourceSection(object.eh_frame_sect_id.?);
+ return @intCast(sect.addr + offset - target_addr + addend);
+ },
+ .x86_64 => return addend,
+ else => unreachable,
+ }
+ }
+
pub fn getCiePointer(rec: Record) u32 {
assert(rec.tag == .fde);
return mem.readIntLittle(u32, rec.data[0..4]);