From 56303d770e8330eb47c12a395ce45e3d448f892d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 13 Jan 2024 12:39:24 +0100 Subject: [PATCH] macho: fix invalid generation of FDE records --- src/link/MachO/UnwindInfo.zig | 33 +++++++++++++++++++++------ src/link/MachO/eh_frame.zig | 4 ++-- test/link/macho/unwind_info/build.zig | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index a993809fd1..ed70b1c083 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -65,6 +65,16 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { const rec = macho_file.getUnwindRecord(index); if (rec.getFde(macho_file)) |fde| { rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset)); + if (fde.getLsdaAtom(macho_file)) |lsda| { + rec.lsda = lsda.atom_index; + rec.lsda_offset = fde.lsda_offset; + rec.enc.setHasLsda(true); + } + const cie = fde.getCie(macho_file); + if (cie.getPersonality(macho_file)) |_| { + const personality_index = try info.getOrPutPersonalityFunction(cie.personality.?.index); // TODO handle error + rec.enc.setPersonalityIndex(personality_index + 1); + } } else if (rec.getPersonality(macho_file)) |_| { const personality_index = try info.getOrPutPersonalityFunction(rec.personality.?); // TODO handle error rec.enc.setPersonalityIndex(personality_index + 1); @@ -232,11 +242,13 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { } // Save records having an LSDA pointer + log.debug("LSDA pointers:", .{}); try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len); for (info.records.items, 0..) |index, i| { const rec = macho_file.getUnwindRecord(index); info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len)); - if (rec.getLsdaAtom(macho_file)) |_| { + if (rec.getLsdaAtom(macho_file)) |lsda| { + log.debug(" @{x} => lsda({d})", .{ rec.getAtomAddress(macho_file), lsda.atom_index }); try info.lsdas.append(gpa, @intCast(i)); } } @@ -367,7 +379,8 @@ pub const Encoding = extern struct { pub fn getMode(enc: Encoding) u4 { comptime assert(macho.UNWIND_ARM64_MODE_MASK == macho.UNWIND_X86_64_MODE_MASK); - return @as(u4, @truncate((enc.enc & macho.UNWIND_ARM64_MODE_MASK) >> 24)); + const shift = comptime @ctz(macho.UNWIND_ARM64_MODE_MASK); + return @as(u4, @truncate((enc.enc & macho.UNWIND_ARM64_MODE_MASK) >> shift)); } pub fn isDwarf(enc: Encoding, macho_file: *MachO) bool { @@ -380,26 +393,32 @@ pub const Encoding = extern struct { } pub fn setMode(enc: *Encoding, mode: anytype) void { - enc.enc |= @as(u32, @intCast(@intFromEnum(mode))) << 24; + comptime assert(macho.UNWIND_ARM64_MODE_MASK == macho.UNWIND_X86_64_MODE_MASK); + const shift = comptime @ctz(macho.UNWIND_ARM64_MODE_MASK); + enc.enc |= @as(u32, @intCast(@intFromEnum(mode))) << shift; } pub fn hasLsda(enc: Encoding) bool { - const has_lsda = @as(u1, @truncate((enc.enc & macho.UNWIND_HAS_LSDA) >> 31)); + const shift = comptime @ctz(macho.UNWIND_HAS_LSDA); + const has_lsda = @as(u1, @truncate((enc.enc & macho.UNWIND_HAS_LSDA) >> shift)); return has_lsda == 1; } pub fn setHasLsda(enc: *Encoding, has_lsda: bool) void { - const mask = @as(u32, @intCast(@intFromBool(has_lsda))) << 31; + const shift = comptime @ctz(macho.UNWIND_HAS_LSDA); + const mask = @as(u32, @intCast(@intFromBool(has_lsda))) << shift; enc.enc |= mask; } pub fn getPersonalityIndex(enc: Encoding) u2 { - const index = @as(u2, @truncate((enc.enc & macho.UNWIND_PERSONALITY_MASK) >> 28)); + const shift = comptime @ctz(macho.UNWIND_PERSONALITY_MASK); + const index = @as(u2, @truncate((enc.enc & macho.UNWIND_PERSONALITY_MASK) >> shift)); return index; } pub fn setPersonalityIndex(enc: *Encoding, index: u2) void { - const mask = @as(u32, @intCast(index)) << 28; + const shift = comptime @ctz(macho.UNWIND_PERSONALITY_MASK); + const mask = @as(u32, @intCast(index)) << shift; enc.enc |= mask; } diff --git a/src/link/MachO/eh_frame.zig b/src/link/MachO/eh_frame.zig index 56d81ba93a..24b3d751a4 100644 --- a/src/link/MachO/eh_frame.zig +++ b/src/link/MachO/eh_frame.zig @@ -426,9 +426,9 @@ pub fn write(macho_file: *MachO, buffer: []u8) void { } if (fde.getLsdaAtom(macho_file)) |atom| { - const offset = fde.out_offset + fde.lsda_offset; + const offset = fde.out_offset + fde.lsda_ptr_offset; const saddr = sect.addr + offset; - const taddr = atom.value; + const taddr = atom.value + fde.lsda_offset; switch (fde.getCie(macho_file).lsda_size.?) { .p32 => std.mem.writeInt( i32, diff --git a/test/link/macho/unwind_info/build.zig b/test/link/macho/unwind_info/build.zig index 534cc4e51a..33af6016f9 100644 --- a/test/link/macho/unwind_info/build.zig +++ b/test/link/macho/unwind_info/build.zig @@ -46,7 +46,7 @@ fn testUnwindInfo( } check.checkInSymtab(); - check.checkContains("(__TEXT,__text) private external ___gxx_personality_v0"); + check.checkContains("(was private external) ___gxx_personality_v0"); test_step.dependOn(&check.step); const run = b.addRunArtifact(exe);