authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-13 04:27:12+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-13 04:27:12+01:00
log7e4c386f6ab5546898b94d80f54e88d45dc6c7b9
treea856f1921d6353ad0e0034a731d3b39c817fdea9
parentf1267e02c49f5d571420d687a6337a85ab76767d
parente835b864e8e5d2ff33b9f59f9f65c74f86093dfc

Merge pull request 'link/MachO: fix eh_frame handling on macOS' (#30768) from vprodan/zig:fix-macos-eh-frame into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30768 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

4 files changed, 58 insertions(+), 14 deletions(-)

src/link/MachO.zig+3-1
......@@ -1707,7 +1707,9 @@ fn initSyntheticSections(self: *MachO) !void {
17071707 } else false;
17081708 if (needs_eh_frame) {
17091709 assert(needs_unwind_info);
1710 self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{});
1710 self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{
1711 .flags = macho.S_COALESCED | macho.S_ATTR_NO_TOC | macho.S_ATTR_STRIP_STATIC_SYMS | macho.S_ATTR_LIVE_SUPPORT,
1712 });
17111713 }
17121714
17131715 if (self.getInternalObject()) |obj| {
src/link/MachO/Object.zig+45-9
......@@ -1298,10 +1298,18 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.
12981298 superposition.getPtr(addr).?.cu = rec_index;
12991299 }
13001300
1301 const FdeRange = struct { start: u64, end: u64 };
1302 var fde_ranges = try std.ArrayList(FdeRange).initCapacity(allocator, self.fdes.items.len);
1303 defer fde_ranges.deinit(allocator);
1304
13011305 for (self.fdes.items, 0..) |fde, fde_index| {
13021306 const atom = fde.getAtom(macho_file);
13031307 const addr = atom.getInputAddress(macho_file) + fde.atom_offset;
13041308 superposition.getPtr(addr).?.fde = @intCast(fde_index);
1309
1310 // Build FDE range for coverage check
1311 const pc_range = fde.pc_range;
1312 fde_ranges.appendAssumeCapacity(.{ .start = addr, .end = addr + pc_range });
13051313 }
13061314
13071315 for (superposition.keys(), superposition.values()) |addr, meta| {
......@@ -1333,15 +1341,43 @@ fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.
13331341 }
13341342 }
13351343 } else if (meta.cu == null and meta.fde == null) {
1336 // Create a null record
1337 const rec_index = try self.addUnwindRecord(allocator);
1338 const rec = self.getUnwindRecord(rec_index);
1339 const atom = self.getAtom(meta.atom).?;
1340 try self.unwind_records_indexes.append(allocator, rec_index);
1341 rec.length = @intCast(meta.size);
1342 rec.atom = meta.atom;
1343 rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file));
1344 rec.file = self.index;
1344 // Check if this address is covered by an existing FDE.
1345 // If so, don't create a null record - let the unwinder fall back to DWARF.
1346 // This is important for local labels within a function that has DWARF unwind info.
1347 const is_covered_by_fde = blk: {
1348 if (fde_ranges.items.len == 0) break :blk false;
1349
1350 // Binary search: find the last FDE where start <= addr
1351 var left: usize = 0;
1352 var right: usize = fde_ranges.items.len;
1353 while (left < right) {
1354 const mid = left + (right - left) / 2;
1355 if (fde_ranges.items[mid].start <= addr) {
1356 left = mid + 1;
1357 } else {
1358 right = mid;
1359 }
1360 }
1361
1362 // Check if the FDE before insertion point covers this address
1363 if (left > 0) {
1364 const range = fde_ranges.items[left - 1];
1365 break :blk addr < range.end;
1366 }
1367 break :blk false;
1368 };
1369
1370 if (!is_covered_by_fde) {
1371 // Create a null record only if not covered by DWARF
1372 const rec_index = try self.addUnwindRecord(allocator);
1373 const rec = self.getUnwindRecord(rec_index);
1374 const atom = self.getAtom(meta.atom).?;
1375 try self.unwind_records_indexes.append(allocator, rec_index);
1376 rec.length = @intCast(meta.size);
1377 rec.atom = meta.atom;
1378 rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file));
1379 rec.file = self.index;
1380 }
13451381 }
13461382 }
13471383
src/link/MachO/eh_frame.zig+7-3
......@@ -116,6 +116,7 @@ pub const Fde = struct {
116116 cie: Cie.Index,
117117 atom: Atom.Index = 0,
118118 atom_offset: u32 = 0,
119 pc_range: u64 = 0,
119120 lsda: Atom.Index = 0,
120121 lsda_offset: u32 = 0,
121122 lsda_ptr_offset: u32 = 0,
......@@ -142,6 +143,9 @@ pub const Fde = struct {
142143 const atom = fde.getAtom(macho_file);
143144 fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
144145
146 // Parse pc_range (function size)
147 fde.pc_range = std.mem.readInt(u64, data[16..][0..8], .little);
148
145149 // Associate with a CIE
146150 const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
147151 const cie_offset = fde.offset + 4 - cie_ptr;
......@@ -350,7 +354,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void {
350354 std.mem.writeInt(
351355 i32,
352356 buffer[offset..][0..4],
353 @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)) + addend),
357 @intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))),
354358 .little,
355359 );
356360 }
......@@ -373,7 +377,7 @@ pub fn write(macho_file: *MachO, buffer: []u8) void {
373377 {
374378 const offset = fde.out_offset + 8;
375379 const saddr = sect.addr + offset;
376 const taddr = fde.getAtom(macho_file).getAddress(macho_file);
380 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
377381 std.mem.writeInt(
378382 i64,
379383 buffer[offset..][0..8],
......@@ -460,7 +464,7 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in
460464 {
461465 const offset = fde.out_offset + 8;
462466 const saddr = sect.addr + offset;
463 const taddr = fde.getAtom(macho_file).getAddress(macho_file);
467 const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
464468 std.mem.writeInt(
465469 i64,
466470 code[offset..][0..8],
src/link/MachO/relocatable.zig+3-1
......@@ -289,7 +289,9 @@ fn initOutputSections(macho_file: *MachO) !void {
289289 } else false;
290290 if (needs_eh_frame) {
291291 assert(needs_unwind_info);
292 macho_file.eh_frame_sect_index = try macho_file.addSection("__TEXT", "__eh_frame", .{});
292 macho_file.eh_frame_sect_index = try macho_file.addSection("__TEXT", "__eh_frame", .{
293 .flags = std.macho.S_COALESCED | std.macho.S_ATTR_NO_TOC | std.macho.S_ATTR_STRIP_STATIC_SYMS | std.macho.S_ATTR_LIVE_SUPPORT,
294 });
293295 }
294296}
295297